简介
SpringMVC概述
SpringMVC是Spring的子框架,是Spring为展现层提供的基于MVC设计理念优秀的web框架,是目前主流的MVC框架。
SpringMVC通过一套MVC注解,让POJO成为处理请求的控制器,而无须实现任何接口。
SpringMV处理请求的原理
客户端发起请求:用户通过浏览器或其他客户端向Spring MVC应用程序发送HTTP请求。
前端控制器接收请求:Spring MVC应用程序的入口点是前端控制器,通常是DispatcherServlet
。前端控制器接收到所有的HTTP请求,并负责协调请求的处理。
处理器映射器(Handler Mapping)确定控制器:前端控制器使用处理器映射器来确定哪个控制器应该处理请求。处理器映射器会根据请求的URL或其他标识来选择适当的控制器。
处理器适配器(Handler Adapter)调用控制器方法:一旦前端控制器确定了要使用的控制器,它将委托给处理器适配器。处理器适配器负责调用控制器的处理方法,并传递请求的参数。控制器方法执行应用程序的业务逻辑,可能会调用服务、访问数据库或进行其他操作。
控制器方法返回模型和视图信息:控制器方法执行完后,它会返回一个模型(Model)对象,该模型包含了要呈现给用户的数据,以及一个逻辑视图名称。这个逻辑视图名称表示视图解析器应该使用哪个视图模板来呈现数据。
视图解析器解析视图名称:前端控制器将逻辑视图名称传递给视图解析器。视图解析器负责将逻辑视图名称解析为实际的视图模板路径。
视图呈现数据:视图根据模型的数据和视图模板生成HTML或其他响应内容,这将作为HTTP响应发送回客户端浏览器。
响应发送给客户端:前端控制器接收到视图生成的响应后,将其发送回客户端浏览器,用户可以在浏览器上看到呈现的页面。
搭建SpringMVC框架
导入jar
<dependencys> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.29</version> </dependency>
<dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.1.2.RELEASE</version> </dependency>
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> </dependencys>
|
编写src/main/webapp/WEB-INF/web.xml
配置文件
<?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <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>
</web-app>
|
创建springmvc.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.acaiblog"></context:component-scan>
<bean id="viewResolver" class="org.thymeleaf.spring5.view.reactive.ThymeleafReactiveViewResolver">
<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="prefix" value="/WEB-INF/views"/> <property name="suffix" value=".html"/>
<property name="characterEncoding" value="UTF-8"/> </bean> </property> </bean> </property> </bean> </beans>
|
编写首页src/main/webapp/WEB-INF/pages/index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <a th:href="@{/HelloController}">发送请求</a> </body> </html>
|
@RequestMapping
为指定的类或方法设置url
注解位置
在类或类方法上面实现@RequestMapping注解
示例代码:
package com.acaiblog.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
@Controller @RequestMapping("/EmpController") public class EmpController { @RequestMapping("/saveEmp") public String saveEmp(){ System.out.print("保存员工信息"); return "success"; } }
|
注解属性
属性 |
类型 |
描述 |
value |
String |
设置url |
path |
String |
与value属性一致 |
method |
RequestMethod |
设置请求方法GET,POST,DELETE等 |
params |
String |
为当前url设置请求参数 |
headers |
String |
为当前url设置请求头信息 |
支持ANT风格路径
常用的通配符
?
匹配一个字符
*
匹配多个字符
**
匹配多层字符
@PathVariable
获取url中占位符的参数
注解位置
在参数的前面
示例代码
请求方法:
<a th:href="@{EmpController/testPathVariadb/1}"></a>
|
处理器方法:
package com.acaiblog.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping;
@Controller @RequestMapping("/EmpController") public class EmpController { @RequestMapping("/test/PathVariadb={id}") public String testPathVariadb(@PathVariable("id") Integer id){ System.out.print(id); return "success"; } }
|
注解属性
属性 |
类型 |
描述 |
value |
String |
设置占位符中的参数名 |
name |
String |
与value属性的作用一致 |
required |
boolean |
设置当前参数是否必须传递参数 |
RESTful CRUD
搭建环境
配置jar依赖
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.1</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.12.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> </dependencies>
|
创建src/main/webapp/WEB-INF/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_4_0.xsd" version="4.0">
<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> </web-app>
|
创建springmvc.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.acaiblog"></context:component-scan>
<bean 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="suffix" value=".html"/> <property name="prefix" value="/WEB-INF/pages/"/> </bean> </property> </bean> </property> </bean> </beans>
|
创建src/main/webapp/WEB-INF/pages/index.html首页
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h2>首页</h2> </body> </html>
|
创建src/main/java/com/acaiblog/controller/ToIndexController.java
package com.acaiblog.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class ToIndexController { @RequestMapping("/") public String toIndexPage(){ return "index"; } }
|
- 添加web模块:IDE》File》Project Structure》Modules》Add》web》
- 添加Artifacts:Add
- 配置tomcat服务
查询增加用户
编辑src/main/webapp/WEB-INF/pages/index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h2>首页</h2> <h3>添加员工</h3> <form th:action="@{emp}" method="post"> <input type="submit" value="添加员工"> </form> <h3>通过id查询员工</h3> <a th:href="@{emp/1001}">查询员工</a> </body> </html>
|
创建src/main/webapp/WEB-INF/pages/success.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>成功页面</title> </head> <body> <h3>添加成功</h3> </body> </html>
|
创建src/main/java/com/acaiblog/controller/EmployeeController.java
package com.acaiblog.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;
@Controller public class EmployeeController { private final static String SUCCESS = "success"; @RequestMapping(value = "/emp",method = RequestMethod.POST) public String saveEmp(){ System.out.print("添加员工"); return SUCCESS; } @RequestMapping(value = "/emp/{id}", method = RequestMethod.GET) public String getEmpById(@PathVariable("id") Integer id){ System.out.printf(String.format("获取员工信息ID: %d", id)); return SUCCESS; } }
|
修改和删除
编辑src/main/webapp/WEB-INF/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_4_0.xsd" version="4.0"> <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> </web-app>
|
编辑index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h2>首页</h2> <h3>修改员工信息</h3> <form th:action="@{/emp/1001}" method="post"> <input type="hidden" name="_method" value="PUT"> <input type="submit" value="修改员工信息"> </form> <h3>删除员工信息</h3> <form th:action="@{/emp/1001}" method="post"> <input type="hidden" name="_method" value="DELETE"> <input type="submit" value="删除员工信息"> </form> </body> </html>
|
编辑src/main/java/com/acaiblog/controller/EmployeeController.java
新增修改和删除的方法
package com.acaiblog.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;
@Controller public class EmployeeController { private final static String SUCCESS = "success"; @RequestMapping(value = "/emp/{id}", method = RequestMethod.PUT) public String updateEmpById(@PathVariable("id") Integer id){ System.out.printf(String.format("修改员工信息ID: %d",id)); return SUCCESS; } @RequestMapping(value = "/emp/{id}", method = RequestMethod.DELETE) public String deleteEmpById(@PathVariable("id") Integer id){ System.out.printf(String.format("删除员工信息ID: %d",id)); return SUCCESS; } }
|
SpringMVC处理请求数据
处理请求参数
自动入参
SpringMVC默认可以将请求参数名与入参参数名一致的参数自动入参。
示例代码
编辑index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h2>首页</h2> <a th:href="@{/getRequestParam(empName='acai')}">获取请求参数</a> </body> </html>
|
编辑src/main/java/com/acaiblog/controller/requestParams.java
package com.acaiblog.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class requestParams { @RequestMapping(value = "/getRequestParam") public void getRequestParam( String empName){ System.out.printf(String.format("员工名称: %s", empName)); } }
|
注解入参
当请求参数和入参名称不一致时,使用@RequestParam注解设置入参参数名。
@RequestParam属性
属性 |
类型 |
描述 |
value |
String |
设置需要入参的参数名 |
name |
String |
与value属性的作用一致 |
required |
Boolean |
设置当前参数是否必须入参 |
defaultValue |
String |
默认参数名 |
pojo入参
使用SpringMVC pojo入参,请求参数名和接受参数名要保持一致区分大小写。
示例代码
创建员工pojosrc/main/java/com/acaiblog/pojo/Employee.java
package com.acaiblog.pojo;
public class Employee { private Integer id; private String name;
public Employee(Integer id, String name, String email, Double salary) { this.id = id; this.name = name; this.email = email; this.salary = salary; }
@Override public String toString() { return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", email='" + email + '\'' + ", salary=" + salary + '}'; }
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Double getSalary() { return salary; }
public void setSalary(Double salary) { this.salary = salary; }
private String email; private Double salary; }
|
编辑index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h2>首页</h2> <h3>处理请求参数</h3> <form th:action="@{/saveEmp}" method="post"> ID:<input type="text" name="id"></br> 姓名:<input type="text" name="name"></br> 邮箱:<input type="text" name="email"></br> 工资:<input type="text" name="salary"></br> <input type="submit" value="创建员工"> </form> </body> </html>
|
编辑src/main/java/com/acaiblog/controller/requestParams.java
创建saveEmp方法
package com.acaiblog.controller;
import com.acaiblog.pojo.Employee; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;
@Controller public class requestParams { @RequestMapping(value = "/saveEmp", method = RequestMethod.POST) public String saveEmp(Employee employee){ System.out.printf(String.format("员工信息: %s", employee)); return "index"; } }
|
返回结果
员工信息: Employee{id=1001, name='acai', email='baocai.guo@qq.com', salary=18000.0}
|
处理请求头
每次发送请求时请求头包含了若干个属性,可以通@RequestHeander注解获取客户端信息,通过@RequestHeander即可将请求头的信息绑定到处理方法的入参中。
@RequestHeander属性
属性 |
类型 |
描述 |
value |
String |
设置需要获取的请求头的名称 |
name |
String |
作用与value一致 |
required |
Boolean |
设置是否必须入参 |
示例代码
编辑index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h2>首页</h2> <h3>处理请求头信息</h3> <a th:href="@{/getHeander}">处理请求头数据</a> </body> </html>
|
编辑src/main/java/com/acaiblog/controller/requestParams.java
创建getHander方法
package com.acaiblog.controller;
import com.acaiblog.pojo.Employee; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;
@Controller public class requestParams { @RequestMapping(value = "/getHeander", method = RequestMethod.GET) public String getHander(@RequestHeader("Host") String hd){ System.out.printf(String.format("请求头数据: %s",hd)); return "index"; } }
|
处理Cookie
通过@CookieValue注解即可将请求头中的Cookie对象绑定到处理方法入参。
@CookieValue属性
属性 |
类型 |
描述 |
value |
String |
设置需要获取的cookie的名称 |
name |
String |
作用与value一致 |
required |
Boolean |
设置是否必须入参 |
示例代码
编辑index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h2>首页</h2> <a th:href="@{/setCookie}">设置cookie</a> <a th:href="@{/getCookie}">获取cookie</a> </body> </html>
|
编辑src/main/java/com/acaiblog/controller/requestParams.java
创建setCookie和getCookie方法
package com.acaiblog.controller;
import com.acaiblog.pojo.Employee; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpSession;
@Controller public class requestParams { @RequestMapping(value = "/setCookie") public String setCookie(HttpSession session){ System.out.printf(String.format("设置session id: %s",session.getId())); return "index";
} @RequestMapping(value = "/getCookie") public String getCookie(@CookieValue("JSESSIONID") String session_id){ System.out.printf(String.format("获取session id: %s", session_id)); return "index"; } }
|
Servlet API处理请求数据
将原生Servelet相关对象入参即可
示例代码
编辑index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h2>首页</h2> <a th:href="@{/getServlet}">使用request对象</a> </body> </html>
|
编辑src/main/java/com/acaiblog/controller/requestParams.java
创建getServlet方法
package com.acaiblog.controller;
import com.acaiblog.pojo.Employee; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.CookieValue; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession;
@Controller public class requestParams { @RequestMapping(value = "/getServlet") public String getServlet(HttpServletRequest request){ ServletContext servletContext = request.getServletContext(); String realPath = servletContext.getRealPath("WEB-INF/pages/index.html"); System.out.printf(String.format("文件路径: %s", realPath)); return "index";
} }
|
SpringMVC处理响应数据
SpringMVC提供了以下两种途径输出模型数据:
- ModelAndView:处理方法返回值为ModelAndView时,方法体即可通过该对象添加模型数据,最终会添加到request中。
- Map或Mode或ModelMap:入参为java.util.map、org.springframwork.ui.Model或org.springframwork.ui.ModelMap时,处理方法返回时,Map中的数据会自动添加到模型中,最终添加到request中。
ModelAndView
示例代码:
@GetMapping("/testMvResponsedata") public ModelAndView testMvResponsedata(){ ModelAndView mv = new ModelAndView(); mv.setViewName("response_success"); mv.addObject("stuName","zhouxu"); return mv; }
|
Model、ModelMap、Map
使用Model、ModelMap、Map作为方法入参,处理响应数据
示例代码:
@GetMapping("/testMapResponsedata") public String testMapResponsedata(Map<String,Object> map { map.put("stuName","zhangsan");
return "response_success"; }
|
SpringMVC中域对象
SpringMVC封装数据,默认使用request域对象,session域的使用。
方式一:
@GetMapping("/testScopeResponsedata") public String testScopeResponsedata(HttpSession session){ session.setAttribute("stuName","xinlai"); return "response_success"; }
|
方式二:
@Controller @SessionAttributes(value = "stuName") public class TestResponseData {
@GetMapping("/testMvResponsedata") public ModelAndView testMvResponsedata(){ ModelAndView mv = new ModelAndView(); mv.setViewName("response_success"); mv.addObject("stuName","zhouxu"); return mv; } }
|
SpringMVC视图
视图解析器对象ViewResolver
- 概述:ViewResolver接口的实现类或子接口,称之为视图解析器
- 作用:将ModelAndView中的View对象解析出来
视图对象View
- 概述:View接口的实现类或子接口,称之为视图对象
- 作用:视图渲染将数据共享域中;跳转路径【转发或重定向】
视图控制器
视图控制器作用:为url映射html页面
编辑spring配置文件springmvc.xml
<mvc:view-controller path="/" view-name="index"/> <mvc:view-controller path="/getServle" view-name="index"/> <mvc:annotation-driven/>
|
加载静态资源
由DefaultServlet
加载静态资源到服务器,比如:html、css、js等资源。
编辑tomcat/conf/web.xml
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
|
DispatcherServlet与DefaultServlet的URL配置均为:/,导致DispatcherServlet中的配置将DefaultServlet配置的/覆盖了【DefaultServlet失效,无法加载静态资源】,解决方案:
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<mvc:annotation-driven></mvc:annotation-driven>
|
重定向
语法:return "redirect:/redirect.html";
编辑index.html页面
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h2>首页</h2> <a th:href="@{/testDirect}">页面重定向</a> </body> </html>
|
编辑处理器方法
package com.acaiblog.controller;
import com.acaiblog.pojo.Employee; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*;
import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession;
@Controller public class requestParams { @GetMapping(value = "/testDirect") public String testDirect(){ System.out.print("页面重定向"); return "redirect:/redirect.html"; } }
|
编辑spring配置文件配置静态页面加载
<mvc:default-servlet-handler/>
|
创建src/main/webapp/redirect.html页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>重定向页面</title> </head> <body> <h3>重定向页面</h3> </body> </html>
|
SpringMVC处理数据
处理请求报文
获取请求报文有两种方式:@RequestBody注解和HttpEntity对象
RequestBody注解
编辑index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h2>请求体</h2> <form th:action="@{/testRequestBody}" method="post"> LastName: <input type="text" name="LastName"></br> Email: <input type="text" name="Email"></br> <input type="submit" value="提交"> </form> </body> </html>
|
编辑处理方法
package com.acaiblog.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class MessageConvertController { @RequestMapping(value = "/testRequestBody")
public String testRequestBody(@RequestBody String request){ System.out.printf(String.format("请求体数据: %s", request)); return "index"; } }
|
HttpEntity对象
示例代码:
package com.acaiblog.controller;
import org.springframework.http.HttpEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class MessageConvertController { @RequestMapping(value = "/testRequestBody") public String testRequestBody(HttpEntity<String> request){ System.out.printf(String.format("请求体数据: %s", request.getBody())); System.out.printf(String.format("请求头数据: %s", request.getHeaders())); return "index"; } }
|
处理响应报文
@ResponseBody注解的作用:将指定数据以直接响应的方式响应数据。比如:使用ResponseBody注解return返回的是数据,不使用ResponseBody注解返回的是页面。
示例代码:
package com.acaiblog.controller;
import org.springframework.http.HttpEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;
@Controller public class MessageConvertController { @RequestMapping(value = "/testRequestBody") @ResponseBody public String testRequestBody(HttpEntity<String> request){ System.out.printf(String.format("请求体数据: %s", request.getBody())); System.out.printf(String.format("请求头数据: %s", request.getHeaders())); return "hello world"; } }
|
SpringMVC消息处理器
消息转换器HttpMessageConverter主要作用:将java对象数据与请求或响应报文相互转换,例如:Java对象转json或json对象转java对象。
导入jar包
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> </dependency>
|
装配MappingJackson2HttpMessageConverter消息转换器,在spring配置文件中添加
创建Emplyee pojo
package com.acaiblog.pojo;
public class Employee { private Integer id; private String name;
public Employee(Integer id, String name, String email, Double salary) { this.id = id; this.name = name; this.email = email; this.salary = salary; }
@Override public String toString() { return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", email='" + email + '\'' + ", salary=" + salary + '}'; }
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Double getSalary() { return salary; }
public void setSalary(Double salary) { this.salary = salary; }
private String email; private Double salary; }
|
使用处理器返回json数据,在方法上面使用@ResponseBody注解
package com.acaiblog.controller;
import com.acaiblog.pojo.Employee; import org.springframework.http.HttpEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;
@Controller public class MessageConvertController { @RequestMapping(value = "/testRequestBody") @ResponseBody public Employee testRequestBody(HttpEntity<String> request){ Employee employee = new Employee(1,"acai","acai@163.com",10000.00); return employee; } }
|
后添加的jar包需要在ide》Project Structure》删除war重新添加,然后运行项目返回以下数据:
{"id":1,"name":"acai","email":"acai@163.com","salary":10000.0}
|
SpringMVC文件上传与下载
文件下载
创建下载文件src/main/webapp/WEB-INF/download/test.txt
编辑index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <a th:href="@{/fileDownload(filename='test.txt')}">文件下载</a> </body> </html>
|
配置下载文件处理器
package com.acaiblog.controller;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; @Controller public class fileDownloadController { @RequestMapping(value = "/fileDownload") @ResponseBody public ResponseEntity<byte[]> fileDownload(HttpServletRequest request, String filename) throws IOException {
String realPath = request.getServletContext().getRealPath("WEB-INF/download/"+filename);
InputStream inputStream = new FileInputStream(realPath);
byte[] bytes = new byte[inputStream.available()];
inputStream.read(bytes);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Dispostion","attachment;filename="+filename); httpHeaders.setContentDispositionFormData("attachment",new String(filename.getBytes("utf-8"),"ISO-8859-1"));
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes,httpHeaders, HttpStatus.OK); return responseEntity; } }
|
文件上传
导入jar包
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.5</version> </dependency>
|
编辑index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/html"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <form th:action="@{/fileUploadController}" method="post" enctype="multipart/form-data"> 上传文件: <input type="file" name="uploadFile"></br> <input type="submit" value="提交"> </form> </body> </html>
|
装配CommonsMultipartResolver
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"/> </bean>
|
编辑处理器方法
package com.acaiblog.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpSession; import java.io.File; import java.io.IOException; import java.util.logging.Logger;
@Controller public class FileUploadController { private static final Logger logger = Logger.getLogger(FileUploadController.class.getName()); @RequestMapping(value = "/fileUplodController") public String fileUploadController(MultipartFile uploadFile, HttpSession session){
String fileName = uploadFile.getOriginalFilename();
String realPath = session.getServletContext().getRealPath("/WEB-INF/upload"); logger.info(String.format("realPath: %s", realPath));
File filePath = new File(realPath); if(!filePath.exists()){ filePath.mkdir(); }
File uFile = new File(filePath+File.separator+ fileName); logger.info(String.format("uFile: %s", uFile)); try { uploadFile.transferTo(uFile); } catch (IOException e) { throw new RuntimeException(e); } return "index"; } }
|
优化文件上传
允许同名文件上传
String uuid = UUID.randomUUID().toString().replace("-", "");
File uFile = new File(filePath+File.separator+uuid+fileName);
|
设置文件上传大小限制
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSizePerFile" value="102400"/> </bean>
|
SpringMVC拦截器
拦截器与过滤器的区别
名称 |
描述 |
作用 |
执行时机 |
过滤器Filter |
属于web服务器组件 |
过滤Servlet请求 |
Servlet前和Servlet后 |
拦截器Interceptor |
属于SpringMVC框架 |
拦截Controller请求 |
执行Servlet之后,Controller之前;执行Controller之后,Servlet之前;执行DispatcherServlet之后 |
拦截器基本概念
SpringMVC可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能。自定义的拦截器可以实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter类。
HandlerInterceptor方法
方法名 |
描述 |
boolean preHandle() |
在请求被处理之前调用,返回 true 表示继续处理,返回 false 表示中断处理。可用于身份验证、日志记录等操作。 |
void postHandle() |
在请求处理之后但在视图渲染之前调用。可以用于修改 ModelAndView 或添加模型属性。 |
void afterCompletion() |
在请求完成处理(包括视图渲染)之后调用。通常用于资源清理、记录日志等操作。 |
拦截器实现
实现拦截器
package com.acaiblog.Interceptor;
import org.springframework.lang.Nullable; 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 { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("执行controller之前"); return true; }
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { System.out.println("执行controller之后"); }
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { System.out.println("渲染视图之后"); }
}
|
装配拦截器
<mvc:interceptors> <bean class="com.acaiblog.Interceptor.MyInterceptor"> </bean> </mvc:interceptors>
|
局部配置拦截器
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/fileUplodController"/> <bean class="com.acaiblog.Interceptor.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors>
|
拦截器的工作原理
单个拦截器工作原理
- 浏览器向服务端发送请求
- 执行拦截器preHandle方法
- 执行controller方法,处理请求响应
- 执行拦截器postHandle方法
- 执行DispatcherServlet渲染视图
- 执行拦截器afterCompletion方法
- 响应数据返回给浏览器
多个拦截器工作原理
- 浏览器向服务端发送请求
- 执行拦截器1
preHandle
方法
- 执行拦截器2
preHandle
方法
- 执行controller方法,处理请求响应
- 执行拦截器2
postHandle
方法
- 执行拦截器1
postHandle
方法
- 执行DispatcherServlet渲染视图
- 执行拦截器2
afterCompletion
方法
- 执行拦截器1
afterCompletion
方法
- 响应数据返回给浏览器
注意:拦截器执行顺序由装配拦截器顺序决定。
SpringMVC异常处理器
为什么需要处理异常
如果程序执行时出现异常为处理,会导致程序终止不会继续往下执行。
SpringMVC中的异常处理器
SpringMVC通过HandlerExceptionResolve处理程序的异常,包括Handler映射,数据绑定以及目标方法执行时发生的异常。常用异常处理器类:DefaultHandlerExceptionResolve、SimpleMappingExceptionResolve
自定义异常处理器
装配异常处理器
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props>
<prop key="java.lang.ArithmeticException">error</prop> </props> </property> </bean>
|
SSM框架整合
spring整合springmvc步骤
创建ssm工程,导入jar包
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.1</version> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.12.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> </dependencies>
|
创建src/main/webapp/WEB-INF/web.xml配置文件
<?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<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>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<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>
<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>
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> </context-param>
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
|
创建src/main/resources/spring.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.acaiblog"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> </beans>
|
创建src/main/resources/springmvc.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.acaiblog"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
<bean 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>
<mvc:view-controller path="/" view-name="index"/>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/> </beans>
|
创建src/main/webapp/WEB-INF/pages/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>首页</title> </head> <body> <h3>首页</h3> </body> </html>
|
IDE配置tomcat测试是否可以正常访问
Spring整合Mybatis
导入jar包
<dependencys> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>5.3.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.3.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>org.mariadb.jdbc</groupId> <artifactId>mariadb-java-client</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.13</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.8</version> </dependency> </dependencys>
|
创建src/main/resources/db.properties配置文件
db.driverClassname=org.mariadb.jdbc.Driver db.url=jdbc:mariadb://localhost:3306/ssm db.username=root db.password=123456
|
编辑src/main/resources/spring.xml配置文件
<beans> <context:property-placeholder location="db.properties"/> <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${db.driverClassname}"/> <property name="url" value="${db.url}"/> <property name="username" value="${db.username}"/> <property name="password" value="${db.password}"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="datasource"/> </bean> <tx:annotation-driven transaction-manager="transactionManager"/> <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="datasource"/> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="typeAliaes" value="com.acaiblog.pojo"/> <property name="mapperLocations" value="classpath:/mapper/*.xml"/> </bean> <mybatis-spring:scan base-package="com.acaiblog.mapper"/> </beans>
|
创建src/main/resources/mybatis-config.xml配置文件
<?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>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="lazyLoadingEnable" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
<setting name="cacheEnabled" value="true"/> </settings>
<plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins> </configuration>
|
创建src/main/java/com/acaiblog/controller/Employee.java
package com.acaiblog.controller;
public class Employee { private Integer id; private String last_name; private String email; private Integer salary;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getLast_name() { return last_name; }
public void setLast_name(String last_name) { this.last_name = last_name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Integer getSalary() { return salary; }
public void setSalary(Integer salary) { this.salary = salary; }
public Employee(Integer id, String last_name, String email, Integer salary) { this.id = id; this.last_name = last_name; this.email = email; this.salary = salary; }
@Override public String toString() { return "Employee{" + "id=" + id + ", last_name='" + last_name + '\'' + ", email='" + email + '\'' + ", salary=" + salary + '}'; } }
|
创建src/main/java/com/acaiblog/mapper/EmployeeMapper.java
package com.acaiblog.mapper;
import com.acaiblog.controller.Employee;
import java.util.List;
public interface EmployeeMapper { public List<Employee> selectAllEmps(); }
|
创建src/main/resources/mapper/EmployeeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.acaiblog.mapper.EmployeeMapper"> <select id="selectAllEmps" resultMap="employee"> select id,last_name,email,salary from employee </select> </mapper>
|
创建src/main/java/com/acaiblog/service/EmployeeService.java
package com.acaiblog.service;
import com.acaiblog.controller.Employee;
import java.util.List;
public interface EmployeeService {
public List<Employee> getEmployees(); }
|
创建src/main/java/com/acaiblog/service/Impl/EmployeeServiceImpl.java
package com.acaiblog.service.Impl;
import com.acaiblog.controller.Employee; import com.acaiblog.mapper.EmployeeMapper; import com.acaiblog.service.EmployeeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;
import java.util.List;
@Service("EmployeeService") public class EmployeeServiceImpl implements EmployeeService { @Autowired private EmployeeMapper employeeMapper; public List<Employee> getEmployees(){ return employeeMapper.selectAllEmps() ; } }
|
创建src/main/java/com/acaiblog/controller/EmployeeController.java
package com.acaiblog.controller;
import com.acaiblog.pojo.Employee; import com.acaiblog.service.EmployeeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping;
import java.util.List; import java.util.Map; import java.util.Objects;
@Controller public class EmployeeController { @Autowired @Qualifier("EmployeeService") private EmployeeService employeeService; @GetMapping("/emps") public String getAllEmps(Map<String, Objects> map){ List<Employee> employees = employeeService.getEmployees(); map.put("emps",employees); return "index"; } }
|