2.SpringMVC学习

2.SpringMVC学习

明廷盛 嘻嘻😁

第一章 学习SpringMVC的切入点

如何切入MVC: ①SpringMVC是JavaWeb的延续 ②MVC(重点是Controller) ③拦截器

  1. Controller: Controller的作用——依据用户发送的请求 ①调用相应的Model ②跳转响应的View

  2. DispatcherServlet: 前端控制器是SpringMVC中心枢纽,它负责协调和控制整个请求处理流程,确保请求能够被正确地处理并生成相应的响应。

  3. 处理乱码

  4. 文件的上传和下载

  5. 拦截器

  6. 异常处理器

  7. SpringMVC工作原理

  8. SSM框架如何整合

image-20220330160253730

image-20240906102543791

第二章 其他

第一节 REST风格的CRUD

  • 传统风格的CRUD(Create, Read, Update, Delete)
功能URL请求方式
/insertEmpPOST
/deleteEmp?empId=1001GET(因为拼接地址栏)
/updateEmpPOST
/selectEmp?empId=1001GET
  • REST风格的CRUD
功能URL请求方式
/empPOST
/emp/1001DELETE
/empPUT
/emp/1001GET
  • REST风格CRUD优势
    • 提高网站排名
      • 排名方式
        • 竞价排名
        • 技术排名
    • 便于第三方平台对接
  • 如何实现PUT&DELETE提交方式
    • 在web.xml中 注册过滤器HiddenHttpMethodFilter
1
2
3
4
5
6
7
8
9
10
<!--  创建HiddenHttpMethodFilter, 并拦截所有-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
  • 设置表单的提交方式为POST ➕第一个input标签的name为_method, value为PUT 或 DELETE
1
2
3
4
5
<form th:action="@{/emp}" method="post">
<!--value值忽略大小写-->
<input type="hidden" name="_method" value="put">
<input type="submit" name="提交"/>
</form>
  • REST风格的URL都一样, 如何区分???
    • 依据提交方式来区分, 不同的提交方式跳转不同的Controller方法

第二节 加载静态资源<mvc:annotation-driven/>

  • 问题引入: ①我们发现如果直接通过重定向, 且文件, 路径都正确, 但还是无法404, 其问题可能是未加载静态资源 ②DefaultServlet是Servlet用于加载静态资源的类, 它往往是全部拦截的<url-pattern>/</url-pattern>③但由于我们在web.xml中设置的<url-pattern>/</url-pattern>是SpringMVC的DispatcherServlet, 此时就会使得DefaultServlet无效, 从而导致静态资源无法加载
  • 解决方法: 在springmvc.xml中加上<mvc:default-servlet-handler/>即可
  • 注意⚠️: 使用后会导致@Controller注解无法识别, 加上<mvc:annotation-driven/>可以解决
1
2
3
4
5
<!--springmvc.xml-->
<!--解决静态资源加载问题-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<!-- 添加上述标签,会导致Controller无法正常使用,需要添加mvc:annotation-driven解决 -->
<mvc:annotation-driven></mvc:annotation-driven>

第三章 Hello SpringMVC

第一节 STEP1: 在Maven项目下搭建WEB工程

第二节 STEP2: Pom.xml配置

  • SpringMVC的视图层使用Thymeleaf实现的, 所以得配置①Thymeleaf和②Spring-webmvc两个包, 但又因为Tomcat还得一个③servlet-api
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!--spring-webmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>

<!-- 导入thymeleaf与spring5的整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>

<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>

第三节 STEP3: web.xml配置

  1. 创建DispatcherServlet Servlet
  2. 为DispatcherServlet初始化参数
  3. 设置创建DispatcherServlet优先级(Servlet的生命周期默认是有请求才会创建对象, 当SpringMVC要求服务器(Tomcat)一启动就创建, 所以要用<load-on-starup>标签设置其优先级)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--1.创建DispatcherServlet Servlet-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--2.为DispatcherServlet初始化参数-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--3.设置创建DispatcherServlet优先级-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

第四节 STEP4: springmvc.xml配置

  • 配置视图解析器本质上就是==配置Thymeleaf==, 其最核心的是==前后缀==, 注意⚠️需要手动要改
  • 关于为什么WEB-INF下的资源可以被访问到
  • ①因为SpringMVC or Thymeleaf 默认都是转发 ②WEB-INF是服务器的私有目录, 无法从浏览器的请求中获取 ③转发本质上是服务器内部发生的跳转 ④重定向是浏览器发送请求给服务器
  • 其他: HTML超链接<a>是通过GET方式提交的, <form>默认也是GET方式提交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--开启组件扫描-->
<context:component-scan base-package="com.mts"/>

<!--配置试图解析器(Thymeleaf)-->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".html"/>
</bean>
</property>
</bean>
</property>
</bean>

第五节 STEP5:编写请求处理器 @Controller

  • html的相关编写省略
1
2
3
4
5
6
7
8
9
10
// 声明当前类是Controller类
@Controller
public class HelloController {

// 当在地址栏输入/时(默认打开时)跳转到"前缀"+ index +"后缀" 这个页面
@RequestMapping("/")
public String toIndex() {
return "index";
}
}

第四章 Controller

第一节 Request—如何对应请求URL

4.1.1 方式一: 使用视图控制器<mvc:view-controller>

  • 语法: <mvc:view-controller path="/" view-name="index"/> springmvc.xml中配置
属性作用
pathURL地址栏
view-name指定的视图(html文件等)
  • 注意⚠️: 使用后会导致@Controller无法识别, 在springmvc.xml中加上<mvc:annotation-driven/>可以解决
  • 示例代码:
1
2
3
4
5
6
<!--springmvc.xml--> 
<!--配置视图控制器-->
<mvc:view-controller path="/" view-name="index"/>

<!-- 解决Controller等注解无法正常使用 -->
<mvc:annotation-driven/>

4.1.2 方式二: 使用@RequestMapping

  • 语法: @RequestMapping 类/方法上增加
属性类型作用
value/pathString[]设置URL信息, 可以写多个(String[ ])
methodString[]为当前URL【类或方法】设置请求方式【POST、DELETE、PUT、GET等】
paramsString[]为当前URL设置请求参数, 如果URL中未携带 报错400
headersString[]为当前URL设置请求头信息, 如URL中未携带相应请求头 报错404
  • 注意⚠️:
    1. ①有@GetMapping等注解, 等同于@RequestMapping(value=”/emps”, method = RequestMethod.GET);
    2. ②这个注解可以用在类上, 比如类上为(“/people”), 方法上为(“/student”), URL=>/people/student;
    3. ③这个支持Ant风格的路径: /?, /*, /**分别匹配 任意一个字符, 任意多字符, 多层路径;
    4. ④params属性 case1:params = "lastName" URL: ….?lastName=Lisi case2:params = "lastName=MTS" URl:必须是 ….?lastName=MTS才行
  • 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RequestMapping(
// 可以通过/saveEmp或/insertEmp来跳转这个方法
value = {"/saveEmp","/insertEmp"},
// 只能通过GET的提交方式来跳转这个方法
method = RequestMethod.GET,
// URL中必须携带lastName这个参数, 且值必须是lisi
params = "lastName=lisi",
// 请求头中Accept的值必须是(包括)application/json才能跳转这个方法
headers = "Accept=application/json"
)
public String saveEmpTest(){
System.out.println("添加员工信息!!!!");
return SUCCESS;
}

第二节 Request—如何获取请求参数

4.2.1 地址栏拼接风格的URL@RequestParam

  • 语法: ①对于名字一致的=>直接入参相同名字即可 且 支持POJO; ②名字不一致的=>需要用@RequestParam指定参数的前面
属性作用
value/name String设置占位符中的参数名
required Boolean设置当前参数是否必须入参【默认值:true】
如果必须入参但没入=>报错; 不必须且没入=>装配null值
  • ! 关于@RequestParam这个注解
    1. 注意可以不加@RequestParam这个注解(当名字相同时)
    2. 如果加了, 这个注解required的参数默认是true, 所以前端不传就是400; 可以设为false解决这个问题,
    3. 建议:如果名称相同, 就不要加了; 如果因为名称不同加了,请把required改为false
  • 示例代码: 普通参数
1
2
3
4
<a th:href="@{/getRequestNormalParam(username='MTS', 
password='12341',
age=4,
money=59.6)}">*地址栏拼接*的request信息</a><br>

1
2
3
4
5
6
7
8
9
10
11
@RequestMapping("/getRequestNormalParam")
public String getRequestMsgNormal(String username,
String password,
Integer age,
@RequestParam("money") Double salary) {
System.out.println("username = " + username);
System.out.println("password = " + password);
System.out.println("age = " + age);
System.out.println("salary = " + salary);
return SUCCESS;
}
  • 示例代码: 普通参数
1
2
3
4
5
6
/*POJO*/
public class Student {
String studentName;
Integer studNum;
Character sex;
}

1
2
3
<a th:href="@{/getRequestPojoParam(studentName='Tom',
studNum=23443,
otherMsg='太厉害啦!')}">获取pojo</a>

1
2
3
4
5
6
7
8
9
//注意:
//1.对于pojo中在request拿不到的数据会置为默认值null
//2.可以和其他普通的参数一并传过来, SpringMVC很智能,但注意名字不要和pojo中的字段撞了
@RequestMapping("/getRequestPojoParam")
public String getRequestMsgPojo(Student student, String otherMsg) {
System.out.println("student = " + student);
System.out.println("otherMsg = " + otherMsg);
return SUCCESS;
}

4.2.2 REST风格的URL@PathVariable

  • 语法: ①对于名字一致的=>自动; ②名字不一致的=>需要用@PathVariable指定
  • 位置: ①直接入参相同名字即可; ②参数的前面
  • 属性: 同上
  • 示例代码:
1
<a th:href="@{/getRequestNormalParam/1001}">*REST风格*的request信息</a><br>

1
2
3
4
5
6
// 这里如果名字相同可以不用注解
@RequestMapping("/getRequestNormalParam/{deptId}")
public String getRequestMsgREST(@PathVariable("deptId") Integer id) {
System.out.println(id);
return SUCCESS;
}

第三节 Request—如何处理请求

4.3.1 获取请求头的内容 @RequestHeader

  • 语法: @RequestHeader("想要获取的在请求头中的属性名称") 这种只能获取单个, 如果想获取全部的请求头可以用HttpEntity<T>入参(见下)
  • 属性: 同上
  • 示例代码:
1
<a th:href="@{/getHeaderMsg}">获取请求头的信息</a>
1
2
3
4
5
6
7
8
/*获取"请求头"中的参数 @RequestHeader*/
@RequestMapping("/getHeaderMsg")
public String getHeaderMsg(@RequestHeader("User-Agent") String userAgent,
@RequestHeader("Host") String host) {
System.out.println("userAgent = " + userAgent);
System.out.println("host = " + host);
return SUCCESS;
}

4.3.2 获取请求体的内容@RequsetBody HttpEntity<T>

  1. 方式一: 使用注解@RequsetBody放在参数前面
    • 语法: @RequsetBody
    • 属性: required 默认是true, 就是如果请求体中没有内容, 页面报错400, 改为false就不会报错;
    • 注意⚠️:请求体👉的是隐藏的, 所以要用POST提交表单
    • 示例代码:
1
2
3
4
5
6
<!--注意要以POST的方式, GET是拼接地址栏, 是获取不到请求体的内容的-->
<form th:action="@{/useRequestBody}" method="post">
lastName:<input type="text" name="lastName"/><br>
password:<input type="text" name="password"/>
<input type="submit" value="使用@RequsetBody注解获取request体"/>
</form>

1
2
3
4
5
@RequestMapping("/useRequestBody")
public String useRequestBody(@RequestBody String body) {
System.out.println("body = " + body);
return SUCCESS;
}
  1. 方式二: 使用HttpEntity<T>作为入参变量
1
2
3
4
5
6
<!--同样需要注意用POST的方式-->
<form th:action="@{/useHttpEntity}" method="post">
lastName:<input type="text" name="lastName"/><br>
password:<input type="text" name="password"/>
<input type="submit" value="使用@RequsetBody注解获取request体"/>
</form>

1
2
3
4
5
6
@RequestMapping("/useHttpEntity")
public String useHttpEntity(HttpEntity<String> httpEntity) {
System.out.println("请求头:"+httpEntity.getHeaders());
System.out.println("请求体:"+httpEntity.getBody());
return SUCCESS;
}

第四节 Repond—跳转到相应的视图 【面向用户】

image-20240727110201263

  1. 从Controller传回DispatchServlet的, 无论String, View的返回值🔙, 最后都会封装为ModelAndView类型
  2. 其中Model保存数据, View保存视图

4.4.1 方式一: 使用String返回

1
2
3
4
@RequestMapping("/success")
public String toSuccess() {
return "success";
}

4.4.2 方式二: 使用ModelAndView返回ModelAndView

1
2
3
4
5
6
7
8
@RequestMapping("/modelAndViewRespond")
public ModelAndView moduleAndViewRespond() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username", "Tom"); // 在request域中存值
//跳转到哪个视图 (等同于原来返回类型String , return "success";
modelAndView.setViewName("success");
return modelAndView;
}

第五节 Repond—返回JSON格式或流【面向前端开发人员】

4.5.1 返回流直接打印在页面中@ResponseBody

image-20240727110828999

  • 语法:@ResponseBody, 方法只能返回String类型
  • 位置: 书写在class类上面【当前类所有方法,均返回文本,不跳转页面】or 书写在方法上面
1
2
3
<h2>使用@ResponseBody注解的方式🔙获取响应体</h2>
<h3>响应体, 可以理解为在页面上展示文字</h3>
<a th:href="@{/responseBody}"> 跳转</a>

1
2
3
4
5
6
@ResponseBody
@RequestMapping("/responseBody")
public String responseBody(HttpServletRequest request, HttpServletResponse response) {
// 因为使用了@ResponseBody注解, 所以这个方法的返回值回直接打印在页面上(仅限String)
return "HelloWord";
}

4.5.2 返回JSON格式的页面信息@ResponseBody

image-20240727111921451

  • 语法: @ResponseBody配置了JSON相关jar包后, 可以返回任意Object类型的数据, 这些数据都会以JOSN页面(content-type=application/json;charset=UTF-8) 的形式返回
  • 步骤
    1. STEP1: 配置pom.xml导入jackson-databind jar包
1
2
3
4
5
6
<!-- jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
  1. STEP2: 在springmvc.xml中添加<mvc:annotation-driven/>
  2. STEP3: 在添加了@ResponseBody注解的类or方法上使用
1
2
<h2>转换为Json格式</h2>
<a th:href="@{/toJson}">跳转</a>

1
2
3
4
5
6
@ResponseBody
@RequestMapping("/toJson")
public Employee toJson(){
Employee employee = new Employee("Tom", "[email protected]", 23.3);
return employee;
}

第六节 Repond—如何向Request域中存值

4.6.1 方式一: 使用原生servlet-api

  • 语法: 这个可以向四大域中存(毕竟是原生api)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RequestMapping("/success")
public String toSuccess(HttpServletRequest request,
HttpServletResponse response) {
// 在request域中存值
request.setAttribute("key", "value");
//在session域中存值
request.getSession().setAttribute("key", "value");
// 在application域中存值
request.getServletContext().setAttribute("key", "value");
// 添加新的cookie
Cookie cookie = new Cookie("key", "value");
response.addCookie(cookie);
return "success";
}

4.6.2 方式二: ModelAndView作为返回值

  • 语法: 默认存在request域中;
1
2
3
4
5
6
7
8
@RequestMapping("/modelAndViewRespond")
public ModelAndView moduleAndViewRespond() {
ModelAndView modelAndView = new ModelAndView();
// 在request域中存值
modelAndView.addObject("username", "Tom");
modelAndView.setViewName("success");
return modelAndView;
}

4.6.3 方式三: 使用Map, Model, ModelMap入参

  • 语法: 三种都是默认存在request域中;
1
2
3
4
5
6
7
8
// java.util.Map
@RequestMapping("/mapRespond")
public String mapRespond(Map<String, Object> map, Model model, ModelMap modelMap) {
map.put("password", 123412); // 在request域中存值
model.addAttribute("gender", "♂"); // 在request域中存值
modelMap.addAttribute("class", "1001"); // 在request域中存值
return "success";
}

第七节 Repond—响应的方式

4.7.1 转发

  • 语法: 默认就是转发

4.7.2 重定向

  • 语法: return “**redirect:/**xxx.html”;
  • 注意⚠️: 重新向用的不是Thymeleaf所以**不能只传递逻辑路径,** redirect:/中的/会被解析为servletContext;
1
2
3
4
5
/*@Controller*/
@RequestMapping("/redirectToSuccess")
public String redirectToSuccess() {
return "redirect:/pages2/success.html";
}

1
2
<!-springmvc.xml--->
<mvc:view-controller path="/redirectToSuccess" view-name="redirect:/pages2/success.html"/>

第五章 处理请求和响应乱码

第一节 实现SpringMVC处理请求和响应乱码CharacterEncodingFilter

  • 思路: SpringMVC处理源码和JavaWeb我们手动处理的思路一致, 都是写个Filter设置字符编码集
  • 步骤: 在web.xml中创建这个CharacterEncodingFilter并设置参数
  • 注意⚠️: 必须是第一过滤器位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--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>
<!--只用配置request的编码, respond已在底层配置好了-->
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

第六章 文件的上传和下载

第一节 实现文件下载ResponseEntity<T>

image-20240726152109574

6.1.1 STEP1: 编写Controller

  1. STEP1: 获取文件的以字节数组byte[]的形式
  2. STEP2: 设置响应头
  3. STEP3: 创建ResponseEntity并设置状态码
1
2
3
4
5
<h1>文件下载</h1>
<!--这里注意,Thymeleaf拼接地址栏等于号=后面要用引号, -->
<a th:href="@{/downloadFile(filename='chang(2).mp4')}">"chang(2).mp4"</a><br>
<a th:href="@{/downloadFile(filename='cover.png')}">"cover.png"</a><br>
<a th:href="@{/downloadFile(filename='遗留问题.md')}">"遗留问题.md"</a>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@RequestMapping("/downloadFile")
public ResponseEntity<byte[]> downloadFile(HttpServletRequest request, String filename) {
ResponseEntity<byte[]> responseEntity = null;

/*STEP1: 获取文件的以字节数组byte[]的形式*/
//使用ServletContext上下文路径获取指定文件的正式绝对路径
String fileRealPath = request.getServletContext().
getRealPath("WEB-INF/download/" + filename);
try (InputStream inputStream = new FileInputStream(fileRealPath)) {
// 创建合适大小的byte[]数组
byte[] bytes = new byte[inputStream.available()];
// 将文件以字节的形式读入bytes数组
inputStream.read(bytes);
/*STEP2: 设置响应头*/
HttpHeaders headers = new HttpHeaders();
//设置要下载的文件名,并告诉浏览器是下载不是打开
headers.add("Content-Disposition", "attachment;filename=" + filename);
headers.setContentDispositionFormData("attachment",
new String(filename.getBytes("utf-8"), "ISO-8859-1"));

/*STEP3: 创建ResponseEntity并设置状态码*/
responseEntity = new ResponseEntity<>(bytes, headers, HttpStatus.OK);
} catch (Exception e) {
System.out.println(e);
}
return responseEntity;
}

第二节 实现文件上传MultipartFile

6.2.1 STEP1: 配置pom.xml

1
2
3
4
5
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>

6.2.2 STEP2: 在springmvc.xml中创建并配置CommonsMultipartResolve解析器

  • 注意⚠️: 这个<bean>的id必需是multipartResolver
1
2
3
4
5
6
<!--springmvc.xml-->
<!--当前bean 的id 值必须是 multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置字符集-->
<property name="defaultEncoding" value="utf-8"></property>
</bean>

6.2.3 STEP3: 准备文件上传的HTML表单(三必须)

  • 表单提交方式 必须为POST
  • 表单属性 必须有enctype=multipart/form-data
  • 表单内容 必须包含文件域【type=file】
1
2
3
4
5
6
7
<form th:action="@{/uploadFile}"
method="post"
enctype="multipart/form-data">
<!--这里的名字要和MultipartFile userUploadFile一致, @PathVariable的知识-->
上传文件: <input type="file" name="userUploadFile"/>
<input type="submit" name="提交"/>
</form>

6.2.4 STEP4: 编写Controller

  1. STEP1: 获取目标文件的原文件名称
  2. STEP2: 获取目标文件需要保存的地址
  3. STEP3: 将用户目标文件移动到需要保存的位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RequestMapping("/uploadFile")
public String uploadFile(MultipartFile userUploadFile, HttpServletRequest request) throws IOException {
// 目标文件=用户上传的文件, 在这里是SpringMVC封装为MultipartFile这个类了

// STEP1: 获取目标文件的原文件名称
System.out.println(userUploadFile);
String filename = userUploadFile.getOriginalFilename();

/* STEP2: 获取目标文件需要保存的地址
e.g.最终文件被保存在
D://IntelliJIDEAWorkBench//StudySpringMVC//Project_7.25_Afternoon//target//Project_7.25_Afternoon//WEB-INF//upload//遗留问题.md
*/
String savePath = request.getServletContext().getRealPath("/WEB-INF/upload/") + "/" + filename;

// STEP3: 将用户目标文件移动到需要保存的位置
userUploadFile.transferTo(new File(savePath));
return "success";
}

第三节 优化文件上传

6.3.1 允许同名文件上传

  • 使用UUID解决文件名字重复的问题
1
2
UUID uuid = UUID.randomUUID(); //  使用UUID解决文件名字重复的问题
String savePath = request.getServletContext().getRealPath("/WEB-INF/upload/") + "/" + uuid + filename;
  • 使用时间戳解决文件名字重复的问题
1
2
3
//自1970年1月1日00:00:00 GMT(UTC时间)起至 当前时间的 毫秒数(ms)
long l = System.currentTimeMillis();
String savePath = request.getServletContext().getRealPath("/WEB-INF/upload/") + "/" + l + filename;

6.3.2 文件上传大小

  • 位置: STEP2的springmvc.xml CommonsMultipartResolver
  • 语法: maxUploadSize; 单位为byte
    • 1 KB = 1024 bytes
    • 1 MB = 1024 KB = 1,048,576 bytes
    • 1 GB = 1024 MB = 1,073,741,824 bytes
1
2
3
4
5
6
7
<!--springmvc.xml-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--设置字符集-->
<property name="defaultEncoding" value="utf-8"></property>
<!-- 设置总文件的大小(byte)-->
<property name="maxUploadSize" value="102400"></property>
</bean>

第七章 拦截器

image-20240727163336778

第一节 SpringMVC拦截器

  • 语法: 实现HandlerInterceptor接口+spingmvc.xml中装配; 实现拦截器两种方式
  • 实现接口:Handlerinterceptor
  • 继承适配器类:HandlerinterceptorAdapter 过时!
  • 辨析: 拦截器与过滤器区别
名称归属作用执行时机及次数
Filterweb服务器组件过滤Servlet请求1.Servlet前
2.Servlet后
InterceptorSpringMVC框架组件拦截Controller请求1.Servlet之后, Controller之前
2.Controller之后, Servlet之前执行
3.DispatcherServlet之后
  1. 多个拦截器的执行流程
    image-20240727164637453
  2. 关于拦截器preHandle()方法返回值对拦截器的影响 【对于某一个拦截器来说, 遵循以下规定(所有前面加上”当前”两个字)】
preHandle()postHandle()afterCompletion()
返回True①在其之后如果没有返回false的preHandle()就会执行,否则不执行
②如果有期间Controller有异常, 不会执行
一定执行
返回false不执行不执行

第二节 实现SpringMVC拦截器 HandlerInterceptor

7.2.1 STEP1: 实现HandlerInterceptor接口, 并重写其三个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Component
public class TestInterceptor1 implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("TestInterceptor11111=>preHandle()");
return false;
}

@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("TestInterceptor11111=>postHandle()");
}

@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
System.out.println("TestInterceptor11111=>afterCompletion()");
}
}

7.2.2 STEP2: 在springmvc.xml中装配<mvc:interceptors>

  • 一个拦截器拦截一个Controller
1
2
3
4
5
6
7
8
<!--springmvc.xml-->
<!--装配了一个拦截器, 用于拦截/interceptor_page的Controller-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/interceptor_page"/>
<ref bean="testInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
  • 多个拦截器拦截一个Controller
1
2
3
4
5
6
7
8
9
10
11
12
<!--springmvc.xml-->
<!--装配了两个拦截器, 都是用于拦截/interceptor_page的Controller-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/interceptor_page"/>
<ref bean="testInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/interceptor_page"/>
<ref bean="testInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
  • 一个拦截器拦截所有Controller
1
2
3
4
5
<!--springmvc.xml-->
<!--因为没有写是拦截哪个URL(哪个Controller)所以拦截所有Controller-->
<mvc:interceptors>
<ref bean="testInterceptor1"/>
</mvc:interceptors>

第八章 异常处理器

SpringMVC中有两个异常处理器实现类

  • DefaultHandleExceptionResolver:默认异常处理器,默认开启,可以支持10+多种异常处理
  • SimpleMappingExceptionResolver: 自定义异常处理, ==将指定的异常映射到指定页面==

第一节 实现SpringMVC异常处理器SimpleMappingExceptionResolver

  • 语法: SimpleMappingExceptionResolver类中有两个关键成员变量
    1. private Properties exceptionMappings;是配置xxx异常=>跳转xxx页面的
    2. private String exceptionAttribute;异常信息的key会放到request域中(默认名字是exception)
  • 注意⚠️: 配置后任意Controller中出现对应的问题都会跳转

8.1.1 STEP1: 在springmvc.xml中装配SimpleMappingExceptionResolver

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--springmvc.xml-->
<!--配置异常处理器 SimpleMappingExceptionResolver-->
<bean id="simpleMappingExceptionResolver"
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<!--配置xxx异常=>跳转xxx页面, 注意使用<prop>标签配置properties属性-->
<props>
<prop key="java.lang.ArithmeticException">error_page</prop>
<prop key="java.lang.NullPointerException">error_page</prop>
</props>
</property>

<!-- 默认的名字为exception, 这里是起别名为ex-->
<property name="exceptionAttribute" value="ex"></property>
</bean>

8.1.2 STEP2: 可以①跳转到指定页面 ②在页面中获取错误信息

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>异常处理器</title>
</head>
<body>
<h1>异常处理器</h1>
<!--从request域中获取错误信息-->
异常信息: <p th:text="${ex}">异常信息s</p>
</body>
</html>

第九章 SpringMVC工作原理

image-20240727220813738

  1. 请求【浏览器向服务器发送请求,携带URL (/testSpringMVCWorking) 】
  2. 通过DispatcherServlet加载SpringMVC容器对象,从而加载Controller【请求处理器】
    • 加载三个对象【HandlerMapping、 HandlerExecutionChain、HandlerAdapter】

第一节 SpringMVC工作原理1【URL不存在】

  1. 判断URL是否存在【不存在】
    • 不存在:判断是否配置mvc:default-servlet-handler
      • 配置:出现404现象,同时提示URL不可用
      • 未配置:出现404现象,但不会提示

第二节 SpringMVC工作原理2 【URL存在】

  1. 判断URL是否存在【存在】
  2. 执行Interceptor【拦截器】第一个方法【preHandle()】
1
2
3
4
//DispatcherServlet的1056行代码
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
  1. 执行Controller 【请求处理器】中的相应方法【处理请求,做出响应】
1
2
3
//DispatcherServlet的1061代码
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  1. 判断Controller中是否存在异常
    • 存在异常
      • 通过HandlerExceptionResolver异常处理器处理异常, 并返回ModelAndView
    • 不存在异常
      • Controller返回ModelAndView
      • 触发拦截器第二个方法【postHandle()】
  2. 通过ViewResolver 【视图解析器对象】将View 【视图对象】从ModelAndView中解析出来
1
2
3
4
5
6
7
8
9
//DispatcherServlet的1435行代码
if (this.viewResolvers != null) {
for (ViewResolver viewResolver: this.viewResolvers) {
view view = viewResolver.resolveviewName(viewName, locale);
if (view != null) {
return view;
}
}
}
  1. View对象开始渲染视图
    • 将数据共享
    • 路径跳转
  2. 执行拦截器第三个方法【afterCompletion()】
1
2
3
4
5
//DispatcherServlet的1157行代码
if (mappedHandler != null) {
// Exception (if any) is already handled..
mappedHandler.triggerAftercompletion(request, response, null);
}
  1. 响应

第十章 SSM框架整合

第一节 Spring+SpringMVC整合步骤

10.1.1 导入jar包

  • springmvc的jar包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--spring-webmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- 导入thymeleaf与spring5的整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>

10.1.2 配置文件

  • web.xml
    1. 注册CharacterEncodingFilter,解决请求乱码问题
    2. 注册HiddenHttpMethodFilter,支持PUT&DELETE提交【REST风格】
    3. 注册DispatcherServlet 【前端控制器】,管理springMVC容器对象
    4. 注册一个上下文参数【contextConfigLocation】 ,设置applicationContext.xml配置文件路径
    5. 注册ContextLoaderListener,管理spring容器对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!--注册CharacterEncodingFilter,解决请求乱码问题-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--注册HiddenHttpMethodFilter,支持PUT&DELETE提交【REST风格】-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!--注册DispatcherServlet 【前端控制器】,管理springMVC容器对象-->
<servlet>
<servlet-name>DispatcherServlet</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>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!--注册一个上下文参数【contextConfigLocation】 ,设置applicationContext.xml配置文件路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>

<!--注册ContextLoaderListener,管理spring容器对象-->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
  • springmvc.xml
    1. 开启组件扫描【只扫描Controller层】
    2. 装配视图解析器
    3. 装配视图控制器【view-controller】
    4. 装配default-servlet-handler,解决静态资源加载问题
    5. 装配annotation-driven,解决后续问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!--开启组件扫描【只扫描Controller层】-->
<context:component-scan base-package="com.mts">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<!--装配视图解析器-->
<bean id="thymeleafViewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine" >
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="characterEncoding" value="UTF-8"/>
<property name="prefix" value="WEB-INF/pages"/>
<property name="suffix" value=".html"/>
</bean>
</property>
</bean>
</property>
</bean>

<!--装配视图控制器【view-controller】-->
<mvc:view-controller path="/index" view-name="index"/>

<!--装配default-servlet-handler,解决静态资源加载问题-->
<mvc:default-servlet-handler/>

<!--装配annotation-driven,解决后续问题-->
<mvc:annotation-driven/>
<!---->
<!---->
<!---->
  1. applicationContex.xml
    • 开启组件扫描【排除Controller层】
1
2
3
4
<!--开启组件扫描【排除Controller层】-->
<context:component-scan base-package="com.mts">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

第二节 Spring+Mybatis整合步骤

10.2.1 导入jar包

  • spring的jar包
  • mybatis的jar包
  • spring与mybatis整合jar包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--spring-jdbc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.1</version>
</dependency>
<!--spring-orm-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.1</version>
</dependency>
<!--spring-aspects-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.1</version>
</dependency>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--导入druid的jar包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--导入mysql的jar包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!--mybatis核心包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--pagehelper分页 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.8</version>
</dependency>

1
2
3
4
5
6
<!--mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>

10.2.2 配置文件

  • applicationContex.xml
    1. 开启组件扫描【排除Controller层】
    2. 加载外部属性文件【db.properties】
    3. 装配数据源【DruidDataSource】
    4. 装配事务管理器【DataSourceTransactionManager】
    5. 开启声明式事务管理注解支持
    6. 装配SqlSessionFactoryBean,管理SqlSessionFactory
    7. 装配MapperScannerConfigurer,管理Mapper代理对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#key=value
db.driverClassName=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/test_mybatis?serverTimezone=UTC
db.username=root
db.password=root
# I advise you better add following into you configuration (2024-07-28)
# Initialize connection
db.initialSize=10
# Maximum number of connections
db.maxActive=50
# Minimum free connection
db.minIdle=5
# Timeout wait time(ms)
db.maxWait=5000

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!--开启组件扫描【排除Controller层】-->
<context:component-scan base-package="com.mts">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

<!--加载外部属性文件【db.properties】-->
<context:property-placeholder location="classpath:db.properties"/>

<!--装配数据源【DruidDataSource】-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="${db.driverClassName}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="initialSize" value="${db.initialSize}"/>
<property name="maxActive" value="${db.maxActive}"/>
<property name="minIdle" value="${db.minIdle}"/>
<property name="maxWait" value="${db.maxWait}"/>
</bean>

<!--装配事务管理器【DataSourceTransactionManager】-->
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!--开启声明式事务管理注解支持-->
<tx:annotation-driven transaction-manager="transactionManager"/>

<!--装配SqlSessionFactoryBean,管理SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--设置数据源-->
<property name="dataSource" ref="dataSource"></property>
<!--设置mybatis-config.xml 核心配置文件路径-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!--设置类型别名-->
<property name="typeAliasesPackage" value="com.mts.pojo"></property>
<!--设置映射文件路径-->
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>

<!--装配MapperScannerConfigurer,管理Mapper代理对象-->
<mybatis-spring:scan base-package="com.mts.mapper"/>
  • mybatis-config.xml
    1. settings 标签
    2. pluggins 标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--settings 标签-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>

<!--pluggins 标签-->
<plugins>
<!--配置PageHelper分页插件-->
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

</configuration>

第一节 Spring+SpringMVC整合步骤

10.1.1 导入jar包

  • springmvc的jar包

10.1.2 配置文件

  1. web.xml
    * 注册CharacterEncodingFilter,解决请求乱码问题
    * 注册HiddenHttpMethodFilter,支持PUT&DELETE提交【REST风格】
    * 注册DispatcherServlet 【前端控制器】,管理springMVC容器对象
    * 注册一个上下文参数【contextConfigLocation】 ,设置applicationContext.xml配置文件路径
    * 注册ContextLoaderListener,管理spring容器对象
  2. springmvc.xml
    * 开启组件扫描【只扫描Controller层】
    * 装配视图解析器
    * 装配视图控制器【view-controller】
    * 装配default-servlet-handler,解决静态资源加载问题
    * 装配annotation-driven,解决后续问题
  3. applicationContex.xml
    * 开启组件扫描【排除Controller层】

第二节 Spring+Mybatis整合步骤

10.2.1 导入jar包

  • spring的jar包
  • mybatis的jar包
  • spring与mybatis整合jar包

10.2.2 配置文件

  1. applicationContex.xml
    * 开启组件扫描【排除Controller层】
    * 加载外部属性文件【db.properties】
    * 装配数据源【DruidDataSource】
    * 装配事务管理器【DataSourceTransactionManager】
    * 开启声明式事务管理注解支持
    * 装配SqlSessionFactoryBean,管理SqlSessionFactory
    * 装配MapperScannerConfigurer,管理Mapper代理对象
  2. mybatis-config.xml
    * settings 标签
    * pluggins 标签
  • Title: 2.SpringMVC学习
  • Author: 明廷盛
  • Created at : 2025-02-15 16:43:31
  • Updated at : 2025-02-15 16:42:00
  • Link: https://blog.20040424.xyz/2025/02/15/😼Java全栈工程师/第三部分 SSM/2.SpringMVC学习/
  • License: All Rights Reserved © 明廷盛