一、SpringMVC介绍
1、概述
- 是最主流的MVC框架
- 是Spring框架中一个WEB子模块
2、定位
定位 |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUSlM6zv-1645584117119)(pic/image-20220104111237036.png)] |
二、快速入门
1、实现步骤
- 创建Maven项目,打包方式war,补全weapp目录
- 导入依赖【spring-webmvc,tomcat7插件依赖】
- 编写一个控制器【普通Java的类】,在控制器中编写一个处理请求的方法【处理器】
- 编写SpringMVC配置文件
- 在web.xml中配置一个前端控制器
- 增加请求页面和响应页面
- 测试:启动tomcat,访问目标接口即可
2、具体实现
2.1 pom.xml
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>80</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
<server>tomcat7</server>
</configuration>
</plugin>
</plugins>
</build>
2.2 控制器
package com.qf.java2107.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello")
public String testHello(){
System.out.println("HelloController testHello");
return "/WEB-INF/pages/success.jsp";
}
}
2.3 springmvc配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.qf.java2107.controller"/>
</beans>
2.4 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.5 请求和响应页面
请求和响应页面 |
---|
![image-20220104112753461](pic/image-20220104112753461.png) |
3、执行流程
执行流程【简易版】 |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TG4zsNnR-1645584117126)(pic/image-20220104141433802.png)] |
三、三大组件
- 前端控制器是如何找到Handler,并让Handler执行,且跳转到响应页面
三大组件 |
---|
![image-20220104143345137](pic/image-20220104143345137.png) |
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
在响应视图时,springmvc会选择视图解析器进行视图解析,最终会进行响应视图的前后缀拼接,所以在Handler中返回视图时,只需要返回视图名称即可。这个视图被称为叫逻辑视图。
四、请求参数封装
1、简单参数
基本类型和包装类型及String
请求参数和处理器的形参名称相同,即可自动封装 |
---|
![image-20220104145354545](pic/image-20220104145354545.png) |
1.1 @RequetParam
- 当请求参数名跟处理器的形参名不一致时,可以使用
@RequetParam
来解决传参问题
@RequestParam : 映射请求参数
name : 请求参数名称
required : 参数是否必须,默认是true,是必须的
defaultValue : required=false时,如果没有传递参数,则使用该默认值
- 可以使用
@RequetParam
标记Map,那么就可以把请求参数全部封装到该Map中,Map的key就是请求参数名,value就是请求参数的值
2、实体参数
请求参数和处理器的形参的属性名相同时,即可自动封装 |
---|
![image-20220104151617390](pic/image-20220104151617390.png) |
- post请求中文乱码,在web.xml中配置过滤器
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、集合类型【了解】
集合必须作为实体的属性存在 |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YL7qvmlu-1645584117128)(pic/image-20220104154454450.png)] |
4、数组
请求参数名跟处理器的形参名相同,即可封装 |
---|
![image-20220104154941232](pic/image-20220104154941232.png) |
5、路径传参
参数在URL中
http://localhost:80/url/zhangsan/10
@PathVariable |
---|
![image-20220104155650429](pic/image-20220104155650429.png) |
6、获取原生ServletAPI
HttpServletRequest、HttpServletResponse、HttpSession
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
获取原生ServletAPI |
---|
![image-20220104160314644](pic/image-20220104160314644.png) |
- 获取HttpServletRequest,也可以当作成员变量注入
获取HttpServletRequest,也可以当作成员变量注入 |
---|
![image-20220104161018314](pic/image-20220104161018314.png) |
7、获取Cookie
获取Cookie【使用Postman测试】 |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QAtyOtXV-1645584117130)(pic/image-20220104161812783.png)] |
五、Handler的返回值
1、String
返回的逻辑视图名
- 带前缀的逻辑视图名
- 请求转发:forward:
- 重定向:redirect:
带前缀的逻辑视图名 |
---|
![image-20220104163032254](pic/image-20220104163032254.png) |
带前缀的逻辑视图名,也可以跳转到另一个处理器 |
---|
![image-20220104163310513](pic/image-20220104163310513.png) |
2、void
默认情况下,返回的是名称为请求URL
的视图
所以在返回值为void时,务必手动跳转视图
原生跳转 |
---|
![image-20220104162703324](pic/image-20220104162703324.png) |
3、ModelAndView
模型和视图:封装模型数据和视图信息的一个由SpringMVC提供的组件
- 模型数据:放在request域对象中
- 视图:可以是视图名称,也可以自定义的视图
ModelAndView |
---|
![image-20220105093120755](pic/image-20220105093120755.png) |
六、响应数据
1、返回值是String
String |
---|
![image-20220105094955515](pic/image-20220105094955515.png) |
2、返回值是void
void |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DcjyvXkV-1645584117133)(pic/image-20220105095026403.png)] |
3、返回值是ModelAndView
ModelAndView |
---|
![image-20220105095109057](pic/image-20220105095109057.png) |
4、Session存储数据
- 原生session传值
- @SessionAttributes【了解】
- 标记在类上,其中可以写存储在Model中的key,作用是把Model的key同时存储在Session中
- 清空数据,可以使用SessionStatus.setComplete() 方法
@SessionAttributes |
---|
![image-20220105095313377](pic/image-20220105095313377.png) |
![image-20220105095332932](pic/image-20220105095332932.png) |
七、处理静态资源
1、原生WEB项目处理静态资源
- 直接放行
- tomcat会把静态资源交给默认的Servlet来处理【org.apache.catalina.servlets.DefaultServlet】,处理方式就是直接放行
2、SpringMVC处理静态资源
- 交给前端控制器来处理,根据请求URL【资源】去找匹配的Handler,找到则交给Handler执行,找不到就出404
3、如何解决
3.1 DispatcherServlet后缀拦截
DispatcherServlet后缀拦截 |
---|
![image-20220105101152709](pic/image-20220105101152709.png) |
3.2 springmvc配置文件
手动告知springmvc,静态资源交给tomcat默认的Servlet来处理 |
---|
![image-20220105101440698](pic/image-20220105101440698.png) |
手动映射静态资源 |
---|
![image-20220105102153209](pic/image-20220105102153209.png) |
八、处理JSON
1、JSON概述
- 是一种前后端的轻量的数据交互格式,不是Java独有
2、两种类型
{
"id":10,
"proName":"iphone13",
"marketDate":"2021-05-05"
}
["lucy", "lily", "tom"]
[
{
"id":10,
"proName":"iphone13",
"marketDate":"2021-05-05"
},
{
"id":11,
"proName":"华为P100",
"marketDate":"2022-01-01"
}
]
{
"id":100,
"username":"zhangwuji",
"girlFirends":["xiaozhao", "zhaoming", "zhouzhirou"],
"cars":[
{"id":1, "price":"300000", "barndName":"BMW"},
{"id":2, "price":"350000", "barndName":"Audi"},
]
}
3、JSON转换工具
- Fastjson:阿里巴巴开源的API
- Jackson:SpringMVC底层选择的
- GSON
- …
4、前台【javascript】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01-json.html</title>
</head>
<body>
</body>
<script>
var product = {
"id":10,
"proName":"iphone13",
"marketDate":"2021-05-05"
};
var proStr = JSON.stringify(product);
var proObject = JSON.parse(proStr);
var jsonStr1 = '[{"id":10,"proName":"iphone13","marketDate":"2021-05-05"},{"id":11,"proName":"华为P100","marketDate":"2022-01-01"}]';
alert(jsonStr1);
alert(typeof jsonStr1);
var jsonObject1 = JSON.parse(jsonStr1);
alert(jsonObject1);
alert(typeof jsonObject1);
</script>
</html>
5、后台【Java】
5.1 Fastjson
package com.qf.java2107.test;
import com.alibaba.fastjson.JSON;
import com.qf.java2107.pojo.Product;
import org.junit.Test;
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class FastjsonTest {
@Test
public void strToListTest() throws Exception {
String str = "[{\n" +
"\t\"id\": 111,\n" +
"\t\"marketDate\": \"2022-01-05\",\n" +
"\t\"proName\": \"大A电视\"\n" +
"}, {\n" +
"\t\"id\": 222,\n" +
"\t\"marketDate\": \"2022-01-05\",\n" +
"\t\"proName\": \"大B电视\"\n" +
"}, {\n" +
"\t\"id\": 333,\n" +
"\t\"marketDate\": \"2022-01-05\",\n" +
"\t\"proName\": \"大C电视\"\n" +
"}, {\n" +
"\t\"id\": 444,\n" +
"\t\"marketDate\": \"2022-01-05\",\n" +
"\t\"proName\": \"大D电视\"\n" +
"}]";
List<Product> products = JSON.parseArray(str, Product.class);
for (Product product : products) {
System.out.println(product);
}
}
@Test
public void strToObjectTest() throws Exception {
String str = "{\"id\":100,\"marketDate\":\"2020-12-12\",\"price\":5000.0,\"proName\":\"海尔冰箱\"}";
Product product = JSON.parseObject(str, Product.class);
System.out.println(product);
String str2 = "{\"id\":100,\"username\":\"jack\"}";
Map<String,Object> map = JSON.parseObject(str2, Map.class);
System.out.println(map);
}
@Test
public void objectToStrTest() throws Exception {
Product product = new Product();
product.setId(100);
product.setProName("海尔冰箱");
product.setPrice(5000D);
product.setMarketDate(new Date());
String jsonStr = JSON.toJSONString(product);
System.out.println(jsonStr);
List<Product> productList = new ArrayList<>();
productList.add(new Product(111, "大A电视", 5555D, new Date()));
productList.add(new Product(222, "大B电视", 55665D, new Date()));
productList.add(new Product(333, "大C电视", 5555D, new Date()));
productList.add(new Product(444, "大D电视", 5555D, new Date()));
String jsonStr2 = JSON.toJSONString(productList);
System.out.println(jsonStr2);
}
}
- 注解:https://blog.csdn.net/weixin_36910300/article/details/79183471
5.2 Jackson
package com.qf.java2107.test;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.java2107.pojo.User;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class JacksonTest {
ObjectMapper objectMapper = new ObjectMapper();
@Test
public void strToListTest() throws Exception {
String str = "[{\"id\":111,\"username\":\"李雷21\",\"birth\":\"2022-01-05\"},{\"id\":123,\"username\":\"李雷22\",\"birth\":\"2022-01-05\"},{\"id\":156,\"username\":\"李雷3\",\"birth\":\"2022-01-05\"}]";
List list = objectMapper.readValue(str, List.class);
System.out.println(list);
List<User> users = objectMapper.readValue(str, new TypeReference<ArrayList<User>>(){});
for (User user : users) {
System.out.println(user);
}
}
@Test
public void strToObjectTest() throws Exception {
String str = "{\"id\":111,\"username\":\"李雷\",\"password\":\"123456\",\"birth\":\"2022-01-05\"}";
User user = objectMapper.readValue(str, User.class);
System.out.println(user);
Map<String,Object> map = objectMapper.readValue(str, Map.class);
System.out.println(map);
}
@Test
public void objectToStringTest() throws Exception {
User user = new User(111, "李雷", "123456", new Date());
String jsonStr = objectMapper.writeValueAsString(user);
System.out.println(jsonStr);
List<User> users = new ArrayList<>();
users.add(new User(111, "李雷21", "123456", new Date()));
users.add(new User(123, "李雷22", "123456", new Date()));
users.add(new User(156, "李雷3", "123456", new Date()));
String jsonStr2 = objectMapper.writeValueAsString(users);
System.out.println(jsonStr2);
}
}
- 注解:https://blog.csdn.net/blwinner/article/details/98532847
6、SpringMVC响应JSON数据
SpringMVC底层默认选择的是Jackson来处理JSON
6.1 实现步骤
- 导入依赖
- 配置注解驱动
- 在Handler上标记一个注解@ResponseBody
- 目标Handler的返回值
- String,直接响应内容
- 对象集合,自动转成JSON响应
@ResponseBody |
---|
![image-20220105142643836](pic/image-20220105142643836.png) |
@ResponseBody是指以响应体的形式直接响应数据给客户端
6.2 @RestController
- 标记在类上,是一个组合注解【@Controller + @ResponseBody】
- 作用就是当前控制器中所有的方法都标记@ResponseBody
@RestController |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w7VculPl-1645584117135)(pic/image-20220105143045112.png)] |
7、SpringMVC接收JSON数据
后台接口 |
---|
![image-20220105143832902](pic/image-20220105143832902.png) |
postman |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-COy1M1D2-1645584117137)(pic/image-20220105143809687.png)] |
- 使用$.ajax来发送ajax请求
- 要求
- 参数type:POST
- 参数data:是JSON格式的字符串【推荐先定义JSON对象,再转成字符串】
- 参数contentType:
application/json;charset=UTF-8
$.ajax({
type : 'POST',
data : '{"id":100,"proName":"我想要新手机100","price":11111.11,"marketDate":"2022-01-05"}',
url : 'test53',
contentType : 'application/json;charset=UTF-8',
dataType : 'json',
success : function (res) {
console.log(res);
if(res.code == 200) {
console.log(res.message);
console.log(res.data.proName);
}
},
error: function () {
alert("error!!");
}
});
var product = {"id":100,"proName":"我想要新手机100","price":11111.11,"marketDate":"2022-01-05"};
$.ajax({
type : 'POST',
data : JSON.stringify(product),
url : 'test53',
contentType : 'application/json;charset=UTF-8',
dataType : 'json',
success : function (res) {
console.log(res);
if(res.code == 200) {
console.log(res.message);
console.log(res.data.proName);
}
},
error: function () {
alert("error!!");
}
});
8、更换JSON转换器
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
九、异常解析器【异常处理器】
1、默认的异常处理机制
默认的异常处理机制 |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GyJtAOQc-1645584117138)(pic/image-20220105161602105.png)] |
2、传统异常处理
传统异常处理【try…catch】 |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XZZ11Z9a-1645584117140)(pic/image-20220105161638818.png)] |
3、Spring的异常处理器
Spring的异常处理器 |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XqXhwl85-1645584117141)(pic/image-20220105162310812.png)] |
4、异常处理机制
4.1 方案一
自定义异常处理器
- 编写异常处理器,实现HandlerExceptionResolver,重写抽象方法【处理异常】
package com.qf.java2107.web.exresolver;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyGlobalResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView mav = new ModelAndView();
mav.setViewName("error");
if(ex instanceof ArithmeticException) {
mav.addObject("errorMessage", "网络异常,请等待!");
return mav;
}
mav.addObject("errorMessage", "服务器正忙,请稍后重试!");
return mav;
}
}
- 把异常处理器注入到SpringMVC容器【springmvc配置文件】
<bean class="com.qf.java2107.web.exresolver.MyGlobalResolver"/>
测试结果 |
---|
![image-20220105163755465](pic/image-20220105163755465.png) |
4.2 方案二
-
两个注解
- @ControllerAdvice:标记在类上,表示当前类是异常处理器
- @ExceptionHandler:标记在方法上,表示处理哪种异常
-
具体实现
package com.qf.java2107.web.ex;
import com.qf.java2107.entity.ResultVO;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class MyControllerAdvice {
@ExceptionHandler(RuntimeException.class)
public ModelAndView handleException1(RuntimeException e){
ModelAndView mav = new ModelAndView("error");
mav.addObject("errorMessage", e.getMessage());
return mav;
}
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public ResultVO handleException2(ArithmeticException e){
return ResultVO.error(e.getMessage());
}
}
Handler该写什么就写什么,抛出的异常会统一交给@ControllerAdvice
标记的类来处理。@ControllerAdvice
必须让SpringMVC能够识别到
十、@RequestMapping
1、概述
2、属性
@RequestMapping(path = {"demo05"}, method = RequestMethod.POST)
public String demo05(){
log.info("Demo01Controller demo05");
return "success";
}
3、标记位置
- 标记在方法上:代表该方法是一个处理器,用来处理对应的请求URL。
- 标记在类上:代表该类中所有的处理器在映射请求时发现先加上类上的@RequestMapping的URL。
类上标记@RequestMapping |
---|
![image-20220106101016989](pic/image-20220106101016989.png) |
十一、RESTFUL
1、概述
-
是一种开发风格,SpringMVC支持
-
以不同的请求方式对应不同的操作
请求方式 | 操作 | URL |
---|
GET | 查询 | /user、/user/1、/user/1/orders |
POST | 新增 | /user |
DELETE | 删除 | /user/1 |
PUT | 更新 | /user |
- 传参
- 简单参数:路径传参【@PathVariable】
- 实体参数:JSON
2、案例
package com.qf.java2107.web.controller;
import com.qf.java2107.entity.ResultVO;
import com.qf.java2107.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@RestController
@Slf4j
public class UserController {
@PostMapping("/users")
public ResultVO save(@RequestBody User user){
log.info("{}",user);
user.setId(100);
return ResultVO.ok("保存成功", user);
}
@DeleteMapping("/users/{id}")
public ResultVO deleteById(@PathVariable("id") Integer id){
log.info("{}",id);
return ResultVO.ok("删除成功", "用户ID:"+id);
}
@PutMapping("/users")
public ResultVO update(@RequestBody User user){
log.info("{}",user);
user.setUsername("updateName");
user.setPassword("updatePassword");
user.setBirth(new Date());
return ResultVO.ok("更新成功", user);
}
@GetMapping("/users")
public ResultVO findAll(){
List<User> users = new ArrayList<>();
users.add(new User(1001, "user1001", "password1001", new Date()));
users.add(new User(1002, "张三", "password1001", new Date()));
users.add(new User(1003, "李四", "password1001", new Date()));
users.add(new User(1004, "小强", "password1001", new Date()));
users.add(new User(1005, "小明", "password1001", new Date()));
return ResultVO.ok("查询成功", users);
}
}
十二、跨域请求
1、域
由协议、IP、端口三部分组成,就叫域
- 同域:协议、IP、端口三部分都相同
- 跨域:协议、IP、端口三部分,有一个或以上不同,则叫跨域
URL | 是否同域 |
---|
http://localhost:80/test1 http://localhost/test2 | 同域 |
http://localhost:80/test1 http://localhost:81/test1 | 跨域 |
http://192.168.1.13:80/test1 http://192.168.1.14:80/test1 | 跨域 |
ftp://192.168.1.13:80/test1 http://192.168.1.13:80/test1 | 跨域 |
2、同源策略
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
3、哪些情况会出现跨域
4、案例演示
4.1 准备
- 准备两台tomcat,部署两个应用
- 应用一:http://localhost:81
- 应用一:http://localhost:82
- 要通过应用一通过Ajax去访问应用二的
/demo01
接口
4.2 解决
4.3 实现
index.jsp |
---|
![image-20220106113241263](pic/image-20220106113241263.png) |
应用二:http://localhost:82
控制器 |
---|
![image-20220106113504374](pic/image-20220106113504374.png) |
十三、拦截器
1、概述
- 是SpringMVC提供一个组件,用于在客户端和目标处理器之间起一个拦截作用
2、跟过滤器的区别
- 过滤器
- WEB开发的规范之一,不是SpringMVC独有的
- 拦截的资源可以是所有,包括静态资源
- 拦截器
- 是SpringMVC的一个组件,只有使用SpringMVC才有拦截器
- 拦截的资源是处理器,不会拦截其他资源
3、自定义拦截器
- 自定义一个类,实现接口
HandlerInterceptor
,重写抽象方法【三个】
package com.qf.java2107.interceptors;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor preHandle------------");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor postHandle------------");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor afterCompletion------------");
}
}
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/js/**"/>
<bean class="com.qf.java2107.interceptors.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
4、拦截器链
- 多个拦截器组合在一起,就是拦截器链
- 默认情况下,是根据拦截器的执行顺序跟配置顺序一致
- 当前拦截的preHandle方法返回true,那么该拦截器的afterCompletion方法是一定会执行的。但是其他方法是否执行需要取决于其他拦截的preHandle的返回值
- 第一个拦截器的preHandle方法返回false,那么就不会执行后续任何资源
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/js/**"/>
<bean class="com.qf.java2107.interceptors.MyInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/demo11"/>
<mvc:exclude-mapping path="/js/**"/>
<bean class="com.qf.java2107.interceptors.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
5、权限拦截案例
package com.qf.java2107.interceptors;
import com.qf.java2107.pojo.User;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object loginUser = request.getSession().getAttribute("loginUser");
if(null != loginUser) {
if(loginUser instanceof User) {
User user = (User) loginUser;
if(!StringUtils.isEmpty(user.getUsername())) {
return true;
}
}
}
response.sendRedirect("/login.jsp");
return false;
}
}
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/js/**"/>
<mvc:exclude-mapping path="/login"/>
<mvc:exclude-mapping path="/register"/>
<bean class="com.qf.java2107.interceptors.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
十四、案例
1、验证码
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<servlet>
<servlet-name>cap</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
<init-param>
<param-name>kaptcha.border</param-name>
<param-value>no</param-value>
</init-param>
<init-param>
<param-name>kaptcha.textproducer.char.length</param-name>
<param-value>4</param-value>
</init-param>
<init-param>
<param-name>kaptcha.textproducer.char.string</param-name>
<param-value>abcdefghijkmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ23456789</param-value>
</init-param>
<init-param>
<param-name>kaptcha.background.clear.to</param-name>
<param-value>211,229,237</param-value>
</init-param>
<init-param>
<param-name>kaptcha.session.key</param-name>
<param-value>captcha</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>cap</servlet-name>
<url-pattern>/captcha</url-pattern>
</servlet-mapping>
login.jsp |
---|
![image-20220106151249939](pic/image-20220106151249939.png) |
2、文件上传
原理:IO读写
- 文件上传是会对Request对象会被重构
- SpringMVC上传文件,主要是通过文件解析器来完成的
-
实现步骤
- 导入依赖【commons-io、common-fileupload】
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="1024000"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
- 客户端【表单:enctype=“multipart/form-data” method=“post”,要指定file域】
<h2>单文件上传</h2>
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="myFile"/><br/>
<input type="submit" value="上传"/>
</form>
<br/>
<h2>多文件上传</h2>
<form action="uploadMore" method="post" enctype="multipart/form-data">
<input type="file" name="myFiles"/><br/>
<input type="file" name="myFiles"/><br/>
<input type="submit" value="上传"/>
</form>
package com.qf.java2107.web.controller;
import com.qf.java2107.entity.ResultVO;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
@RestController
public class FileUploadController {
@RequestMapping("/upload")
public ResultVO upload(MultipartFile myFile, HttpSession session){
try {
if(null == myFile) {
return ResultVO.error("文件不能为空");
}
String filename = myFile.getOriginalFilename();
if(StringUtils.isEmpty(filename)) {
return ResultVO.error("文件不能为空");
}
String extName = filename.substring(filename.lastIndexOf("."));
String detFilename = UUID.randomUUID().toString().replace("-", "").concat(extName);
String path = session.getServletContext().getRealPath("/upload_files");
File file = new File(path, detFilename);
if(!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
myFile.transferTo(file);
return ResultVO.ok("文件上传成功", path);
} catch (IOException e) {
e.printStackTrace();
}
return ResultVO.error("文件上传失败", "未知异常");
}
@RequestMapping("/uploadMore")
public ResultVO uploadMore(MultipartFile[] myFiles, HttpSession session){
try {
if(null == myFiles) {
return ResultVO.error("文件不能为空");
}
for (int i = 0; i < myFiles.length; i++) {
String filename = myFiles[i].getOriginalFilename();
if(StringUtils.isEmpty(filename)) {
return ResultVO.error("文件不能为空");
}
String extName = filename.substring(filename.lastIndexOf("."));
String detFilename = UUID.randomUUID().toString().replace("-", "").concat(extName);
String path = session.getServletContext().getRealPath("/upload_files");
System.out.println(path);
File file = new File(path, detFilename);
if(!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
myFiles[i].transferTo(file);
}
return ResultVO.ok("文件上传成功");
} catch (IOException e) {
e.printStackTrace();
}
return ResultVO.error("文件上传失败", "未知异常");
}
}
3、文件下载
原理:浏览器能解析就打开,不能解析就下载
指定要下载的文件:告知浏览器不要解析该文件
设置一个响应头就好了
<h2>要下载美女的图片吗?</h2>
美女1 <a href="download?filename=072f6c8c448d4514b44d7267be914e21.jpg">下载</a><br/>
美女2 <a href="download?filename=846a4cf4e8e748c599e0bf2eb75d465f.jpg">下载</a><br/>
美女3 <a href="download?filename=f3e4610a5f5846e4acebdb98f0231f92.jpg">下载</a><br/>
控制器 |
---|
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ovIVTW9J-1645584117144)(pic/image-20220106163533695.png)] |
十五、SpringMVC执行流程
SpringMVC执行流程 |
---|
![image-20220107092849365](pic/image-20220107092849365.png) |
十六、SSM整合
1、Spring、SpringMVC、Mybaits整合
2、Spring整合SpringMVC
2.1 整合后,会出现两个容器
- Spring容器【父容器】
- SpringMVC容器【子容器】
父子容器 |
---|
![image-20220107111927571](pic/image-20220107111927571.png) |
2.2 怎么整合?
-
子容器什么时候初始化?
-
父容器什么时候初始化?
- tomcat启动时初始化WEB应用,初始化ServletContext域对象【ServletContextListener】
- 因为Spring写了一个监听器【ContextLoaderListener】,放Spring容器放到了ServletContext中
-
容器放哪里?
- ServletContext:整个WEB应用
- ServletContext.setAttrbute();
-
pom.xml
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>80</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
<server>tomcat7</server>
</configuration>
</plugin>
</plugins>
</build>