SpringMVC
概述
-
SpringMVC是基于spring的,是spring中的一个模块,做web开发使用的。
-
SpringMVC叫做spring web mvc说明他是spring的核心技术,做web开发,springmvc内部是使用mvc架构模式。
-
SpringMVC是一个容器,使用IOC技术,管理界面层中的控制器对象。
-
SpringMVC底层是一个servlet,可以接收请求,处理请求,显示处理给用户。
MVC指:M模块层、V视图层、C控制层,这样的设计理念,而SSM框架里面SPRING MVC本身就是MVC框架,作用是帮助(某种意义上也可以 理解为约束)我们要按照MVC这样的设计来开发WEB项目
处理用户请求流程:
- 用户发请求—>SpringMVC—>Spring—>Mybatis—>数据库
SpringMVC中的核心Servlet是DispatcherServlet
- DispatcherServlet是一个Servlet对象,负责接收请求,响应处理结果。
- DispatcherServlet的父类是HttpServlet
- DispatcherServlet也叫做前端控制器
SpringMVC是管理控制器对象,原来没有SpringMVC之前使用Servlet作为控制器对象使用。现在通过SpringMVC容器创建—种叫做控制器的对象,代替Servler行使控制器的角色、功能。
项目结构
特点
- Spring家族原生产品,与IOC容器等基础设施无缝对接
- 基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统—处理
- 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
- 代码清新简洁,大幅度提升开发效率
- 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
- 性能卓著,尤其适合现代大型、超大型互联网项目要求
第一个SpringMVC程序
开发步骤:
- 1.新建一个基本maven工程
- 2.导入相关jar包
- 3.编写web.xml,注册DispatcherServlet
- 4.编写springmvc配置文件
- 5.接下来就是去创建对应的控制类,coatroller
- 6.最后完善前端视图和controller之间的对应
- 7.测试运行调试.
添加依赖
<dependencies>
<!--SpringMVC开发-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<!--ServletAPI-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--logback日志包-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>
<!--junit测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory> <!--所在的目录-->
<includes><!--包括目录下的.properties、.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include> **/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
配置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">
<!-- 1、配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--通过初始化参数指定SpringMVC配置文件的位置-->
<init-param>
<!-- contextConfigLocation为固定值 -->
<param-name>contextConfigLocation</param-name>
<!-- classpath:表示从类路径查找配置文件 -->
<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>
<!--2、解决请求和响应参数乱码问题-->
<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>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
注意:springmvc中拦截所有请求是 “/” ,而不是"/*"
/:所匹配的请求可以是/login或.html或.js或.css方式的请求路径,但是/不能匹配.jsp请求路径的请求,因此就可以避免在访问jsp页面时,该请求被DispatcherServlet处理,从而找不到相应的页面
/*:则能够匹配所有请求(包括.jsp请求),例如在使用过滤器时,若需要对所有请求进行过滤,就需要使用/*的写法
springmvc配置文件
在resource目录下创建springMVC配置文件
<?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
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--扫描组件,主要扫描controller层-->
<context:component-scan base-package="com.wei.controller"/>
<!--让springmvc不处理静态资源,如:.html .css .js .jpg...-->
<mvc:default-servlet-handler/>
<!--开启注解驱动,以使得访问路径与方法的匹配可以通过注解配置-->
<mvc:annotation-driven >
<mvc:message-converters>
<!-- 处理响应中文内容乱码 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="UTF-8" />
<property name="supportedMediaTypes">
<list>
<value>text/html</value>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
编写控制器类
创建controller包,在包下面创建HelloController类,加上@Controller表示他是一个控制器类
@Controller
@RequestMapping("/hello")
public class HelloController {
//访问路径: localhost:8080/hello/h1
@RequestMapping("/h1")
public String hello01(){
return "hello"; //会被视图解析器处理
}
}
当用户输入localhost:8080/hello/h1(因为有两个RequestMapping)
这里返回的字符串hello,会被上面适配的视图解析器解析,将前缀和后缀给它加上变为/WEB-INF/jsp/hello.jsp,得到一个完整的路径,即将WEB-INF下jsp目录下的hello.jsp页面返回给用户
SpringMVC组件解析
1 相关组件
- 前端控制器:DispatcherServlet(不需要程序员开发)
- 作用:接收请求,响应结果,相当于转发器,中央处理器。
有了DispatcherServlet减少了其它组件之间的耦合度。
- 作用:接收请求,响应结果,相当于转发器,中央处理器。
- 处理器映射器:HandlerMapping (不需要程序员开发)
- 作用:根据请求的url查找Handler
- 处理器适配器: HandlerAdapter
- 作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
- 处理器:Handler (需要程序员开发)
- 注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
- 视图解析器:View Resolver (不需要程序员开发)
- 作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
- 视图: View (需要程序员开发,如 jsp页面)
- View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
@RequestMapping注解
标识一个类:设置映射请求的请求路径的初始信息
标识一个方法:设置映射请求请求路径的具体信息
value属性:
设置请求地址,是一个数组,如 value = “{ /h1,/h2…}”,当只有一个请求地址时,{}可以省略(必须设置)
@RequestMapping(value = "/h1")
public String hello01(){
return "hello";
}
method属性:
设置请求的方式,是一个数组,不设置默认匹配所有请求
- RequestMethod.GET
- RequestMethod.POST
- RequestMethod.PUT
- RequestMethod.DELETE
- 其实对于处理指定请求方式的控制器方法,SpringMVC提供了@RequestMapping的派生注解
- 处理get请求 —> @GetMapping
- 处理post请求 —> @PostMapping
- 处理put请求 —> @PutMapping
- 处理delete请求—> @DeleteMapping
@RequestMapping(value = "/h1", method = {RequestMethod.GET,RequestMethod.POST})
public String hello01(){
return "hello"; //会被视图解析器处理
}
params属性:
用于限定请求参数条件,它支持简单的表达式。要求请求参数的key和value必须和配置的一模─样
例如:params = {“username”}:请求参数中必须有username
params = {“!username”}:请求参数中不能有username
params = {“money == 100”}:表示请求参数必须有money,且money的值必须是100
params = {“money != 100”}:表示请求参数必须有money,且money的值不能是100
@RequestMapping(value = "/h1",params = {"username"})
public String hello01(){
return "hello"; //会被视图解析器处理
}
headers属性:
通过请求头来匹配请求映射,是一个数组
例如:headers = {“Host”}:请求头必须有Host
headers = {“!Host”}:请求头不能有Host
headers = {“Host != localhost:8081”}:请求头必须有Host,且值不能是localhost:8081
headers = {“Host == localhost:8080”}:请求头必须有Host,且值必须是localhost:8080
@RequestMapping(value = "/h1",headers = {"Host==localhost:8080"})
public String hello01(){
return "hello"; //会被视图解析器处理
}
ant风格路径
springMVC支持使用ant风格路径匹配
? :表示任意的单个字符,@RequestMapping(value = "/h?/h1)"
*:表示任意的0个或多个字符,@RequestMapping(value = "/h*/h1)"
**:表示任意的一层或多层目录,@RequestMapping(value = "/**/h1)"
注意:在使用**时,只能使用/**/xxx的方式
占位符
SpringMVC支持路径中的占位符
原始方式:/deleteUser?id=1
rest方式:/deleteUser/1
SpringMVC路径中的占位符常用于restful风格中,当请求路径中将某些数据通过路径的方式传输到服务器中,就可以在相应的**@RequestMapping注解的value属性中通过占位符{xx}表示传输的数据,在通过@PathVariable**注解,将占位符所表示的数据赋值给控制器方法的形参
@RequestMapping("/testRest/{id}/{username}")
public String testRest(@PathVariable("id") String id,@PathVariable("username") String username){
System.out.println("id:" + id);
System.out.println("username" + username);
return "success";
}
请求路径:localhost:8080:/testRest/110/张三
结果:
id:110
username:张三
获取请求参数
1、通过ServletAPI获取
将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest req){
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("username:" + username);
System.out.println("password:"+password);
return "success";
}
请求路径:localhost:8080:/testServletAPI?username=张三&password=123456
结果
username:张三
password:123456
2、通过方法的形参获取
在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参
请求参数中出现多个同名参数,可以使用数组或字符串来接收
如果使用字符串接收,则将多个值通过,进行拼接
@RequestMapping("/testParam")
public String testParam(String username ,String password,String[] hobby){
//请求参数中出现多个同名参数,可以使用数组或字符串来接收
//如果使用字符串接收,则将多个值通过,进行拼接
System.out.println("username:" + username);
System.out.println("password:"+password);
System.out.println("hobby:"+Array.toString(hobby));
return "success";
}
请求路径:localhost:8080:/testServletAPI?username=张三&password=123456&hobby=a&hobby=b
结果
username:张三
password:123456
hobby:[a, b]
3、通过方法的形参获取2
如果请求参数和方法形参不同名也需要通过方法的形参来获取请求参数的值,则需要使用**@RequestParam**注解
@RequestMapping("/testParam")
public String testParam(@RequestParam("myname") String username ,String password,String[] hobby){
//username接收参数名为myname的值
System.out.println("username:" + username);
System.out.println("password:" + password);
System.out.println("hobby:" + Array.toString(hobby));
return "success";
}
请求路径:localhost:8080:/testServletAPI?myname=张三&password=123456&hobby=a&hobby=b
结果
username:张三
password:123456
hobby:[a, b]
如果使用了@RequestParam注解,则表示注解中的请求参数是必须传递的,如果不一定需要传输,则设置其required属性为false
@RequestMapping("/testParam")
public String testParam(@RequestParam(value = "myname", required = false) String username,
String password,String[] hobby)
{
//username接收参数名为myname的值
System.out.println("username:" + username);
System.out.println("password:"+password);
System.out.println("hobby:"+Array.toString(hobby));
return "success";
}
也可以设置默认值,即不传递myname时,设置一个默认值给username接收
@RequestMapping("/testParam")
public String testParam(@RequestParam(value = "myname", required = false,defaultValue = "李四")
String username,String password,String[] hobby){
//username接收参数名为myname的值
System.out.println("username:" + username);
System.out.println("password:"+password);
System.out.println("hobby:"+Array.toString(hobby));
return "success";
}
4、@RequestHeader注解
@RequestHeader注解将请求头信息和方法形参建立映射关系,作用与@RequestParam注解类似
@RequestHeader有三个属性:value、requied、defaultValue,使用也和@RequestParam的属性相同
5、@CookieValue注解
@RequestHeader注解将cookie数据和方法形参建立映射关系,作用与@RequestParam注解类似
@RequestHeader有三个属性:value、requied、defaultValue,使用也和@RequestParam的属性相同
6、通过POJO获取请求参数
可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参教就会为此属性赋值
<form action="localhost:8080/testPOJO" method="post">
用户名:<input type="text" name="username"/><br>
密码: <input type="password" name="password"/><br>
性别:<input type="radio" name="sex" value="男">
<input type="radio" name="sex" value="女"/><br>
年龄:<input type="text" name="age"/><br>
邮箱:<input type="text" name="email"/><br>
<input type="submit" value="提交">
</form>
实体类对象,属性名对应form表单中的name
public class User {
private String username;
private String password;
private Integer age;
private String sex;
private String email;
public User() {
}
public User(String username, String password, Integer age, String sex, String email) {
this.username = username;
this.password = password;
this.age = age;
this.sex = sex;
this.email = email;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", email='" + email + '\'' +
'}';
}
//省略set和get方法...
}
@RequestMapping("/testPOJO")
public String testPOJO(User user){
System.out.println(user);
return "success";
}
域对象共享数据
1、向request域中共享数据
方式一:使用servletAPI
@RequestMapping(value = "/test01")
public String test01(HttpServletRequest req){
req.setAttribute("key1","value1");
return "success";
}
方式二:使用ModelAndView
@RequestMapping(value = "/test02")
public ModelAndView test02(){
/*
* ModelAndView有model和view的功能
* Model主要用于共享数据
* View主要用于实现页面跳转
*
*/
ModelAndView mv = new ModelAndView();
//共享数据
mv.addObject("key2","value2");
//指定要跳转的视图名称
mv.setViewName("success"); //跳转到success页面
return mv;
}
方式三:使用Model
@RequestMapping(value = "/test03")
public String test03(Model model){
//向request域中添加数据
model.addAttribute("key3","value3");
//跳转到success页面
return "success";
}
方式四:使用map
@RequestMapping(value = "/test04")
public String test04(Map<String,Object> map){
//向request域中添加数据
map.put("key4","value4");
//跳转到success页面
return "success";
}
方式五:使用ModelMap
@RequestMapping(value = "/test05")
public String test05(ModelMap modelMap){
//向request域中添加数据
modelMap.addAttribute("key5","value5");
//跳转到success页面
return "success";
}
探究Model、ModelMap、Map之间的关系
Model、ModelMap、Map类型的参数其实本质上都是BindingAwareModelMap类型的
public iterface MOdel() {}
public class ModelMap extends LinkHashMap<String,Object> {}
public class ExtendModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}
2、向session域共享数据
推荐使用servletAPI
@RequestMapping(value = "/test01")
public String test01(HttpSession session){
session.setAttribute("key1","value1");
return "success";
}
3、向Application域中共享数据
推荐使用servletAPI
@RequestMapping(value = "/test01")
public String test01(HttpSession session){
ServletContext application = session.getServletContext();
//向Application域中共享数据
application.setAttribute("key1","value1");
return "success";
}
RESTFul
HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。
它们分劓对应四种基本操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。
REST风格提倡URL地址使用统一的风格设计,从前到后各个单词使用斜杠"/“分开,不使用问号”?"键值对方式携带请求参数,而是将要发送给服务器的数据作为URL地址的一部分,以保证整体风格的一致性。
要使springMVC接收put和delete请求,需要配置web.xml文件,设置一个过滤器,该过滤器得写在请求和响应参数乱码过滤器下面,不然请求和响应参数乱码会失效
<!--配置HiddenHttpMethodFilter,用来支持put和delete请求-->
<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>
1、测试get
查询所有用户
<a href="${pageContext.request.contextPath}/testGet1">查询所有用户(get请求)</a>
//查找所有用户
@RequestMapping(value = "/testGet1",method = RequestMethod.GET)
public String testGet1(){
System.out.println("查询所有用户信息");
//逻辑代码....
return "success";
}
按照id查询用户
<a href="${pageContext.request.contextPath}/testGet2/id=001">按照id来查询用户信息(get请求)</a>
//根据id查找所有用户
@RequestMapping(value = "/testGet2/{uid}",method = RequestMethod.GET)
public String testGet2(@PathVariable("uid") String uid){
System.out.println("根据用户id来查询用户");
System.out.println(uid);
return "success";
}
2、测试post
添加用户
<form action="${pageContext.request.contextPath}/testPost" method="post">
用户名:<input type="text" name="username"/><br>
密码: <input type="password" name="password"/><br>
性别:<input type="radio" name="sex" value="男">男
<input type="radio" name="sex" value="女"/>女<br>
年龄:<input type="text" name="age"/><br>
邮箱:<input type="text" name="email"/><br>
<input type="submit" value="提交">
</form>
//添加用户
@RequestMapping(value = "/testPost",method = RequestMethod.POST)
public String testPost(User user){
System.out.println("添加用户");
System.out.println(user);
return "success";
}
3、测试put
修改用户
<form action="${pageContext.request.contextPath}/testPut" method="post">
<input type="hidden" name="_method" value="PUT"/>
用户名:<input type="text" name="username"/><br>
密码: <input type="password" name="password"/><br>
性别:<input type="radio" name="sex" value="男">男
<input type="radio" name="sex" value="女"/>女<br>
年龄:<input type="text" name="age"/><br>
邮箱:<input type="text" name="email"/><br>
<input type="submit" value="提交">
</form>
//修改用户
@RequestMapping(value = "/testPut",method = RequestMethod.PUT)
public String testPut(User user){
System.out.println("修改用户");
System.out.println(user);
return "success";
}
4、测试delete
按照id删除用户
<!--a标签控制表单提交delete请求-->
<a id="testDelete" href="${pageContext.request.contextPath}/testDelete/id=002">根据id删除用户</a>
<form id="delete" method="post">
<input type="hidden" name="_method" value="DELETE"/>
</form>
<script>
var a = document.getElementById("testDelete");//获取a标签
var form = document.getElementById("delete");//获取表单
a.onclick = function (){
form.action = a.href; //设置表单提交的路径
console.log("a.href",a.href)
console.log(form.action);
//提交表单
form.submit();
//阻止a标签提交
return false;
}
</script>
//根据id删除用户
@RequestMapping(value = "/testDelete/{id}",method = RequestMethod.DELETE)
public String testDelete(@PathVariable("id") String id){
System.out.println("删除用户");
System.out.println(id);
return "success";
}
处理静态资源
在springmvc.xml中加入以下代码
<!--开放对静态资源的访问,DispatcherServlet处理不了给defaultServlet处理-->
<mvc:default-servlet-handler/>
<!--开启mvc注解驱动-->
<mvc:annotation-driven/>
HttpMessageConverter
HttpMessageConverter,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报文
HttpMessageConverter提供了两个注解和两个类型:@RequestBody,@ResponseBody,RequestEntity,ResponseEntity
@RequestBody
该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上 ,再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上
需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值
<form action="${pageContext.request.contextPath}/testRequestBody" method="get">
用户名:<input type="text" name="username"/><br>
密码:<input type="password" name="password"/>
<input type="submit" value="提交"/>
</form>
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String requestBody){
System.out.println("reqestBody:" + requestBody);
return "success";
}
RequestEntity
RequestEntity封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过getHeaders()获取请求头信息,通过getBody()获取请求体信息
<form action="${pageContext.request.contextPath}/testRequestEntity" method="get">
用户名:<input type="text" name="username"/><br>
密码:<input type="password" name="password"/>
<input type="submit" value="提交"/>
</form>
@RequestMapping("/testRequestEntity")
public String testRequestEntity(@RequestBody String requestBody){
System.out.println("reqestBody:" + requestBody);
return "success";
}
@ResponseBody
该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区
<a href="${pageContext.request.contextPath}/testResponseBody">测试</a>
@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
//不会被视图解析器解析
return "你好";
}
处理json:如果要返回的不是字符传,而是对象,需要将java对象转为json字符串,再进行返回
步骤如下:
1、导入jackson依赖
<!--导入jackson依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
2、在SpringMVC的核心配置文件中开启mvc的注解驱动,此时在HandlerAdaptor中会自动装配一个消息转换器Mappinglackson2HttpMessageConverter,可以将响应到浏览器的Java对象转换为json格式的字符串
<!--开启mvc注解驱动-->
<mvc:annotation-driven/>
3、在处理器方法上使用@ResponseBody注解进行标识
4、将Java对象直接作为控制器方法的返回值返回,就会自动转换为json格式的字符串
@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
//不会被视图解析器解析
User user = new User("001","张三","18");
return user;
}
结果
{“id”:001,“name”:“张三”,“age”:18}
ResponseEntity
ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文
拦截器
SpringMVC中的拦截器用于拦截控制器方法的执行
SpringMVC中的拦截器需要实现HandlerInterceptor或者继承HandlerInterceptorAdapter类
SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置
设置拦截器步骤:
1、编写一个自己的拦截器(需实现HandlerInterceptor类)
public class MyInterceptor implements HandlerInterceptor {
//要拦截的逻辑代码写在这个方法中
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("经过该拦截器");
return true; //返回false表示拦截,返回true表示放行
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle-----------");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion-----------");
}
}
2、在springmvc配置文件中配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--设置拦截路径-->
<mvc:mapping path="/**"/>
<!--设置排除的路径-->
<mvc:exclude-mapping path="/"/>
<bean class="com.wei.interceptors.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
拦截器中的3个抽象方法
preHandle:在控制器方法执行之前执行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法
postHandle:在控制器方法执行之后执行
afterCompletion:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()
多个拦截器执行顺序
1、若每个拦截器的preHandle()都返回true
此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关;
**preHandle()**会按照配置的顺序执行
而**postHandle()和afterComplation()**会按照配置的反序执行
2、若某个拦截器的preHandle()返回了false
preHandle()返回false和它之前的拦截器的preHandle()都会执行,postHandle()都不执行,返回false的拦截器之前的拦截器的afterComplation()会执行
异常处理器
1、springmvc配置文件方式
SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口: HandlerExceptionResolverHandlerExceptionResolver接口的实
现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver
SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver
<!--配置异常处理-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings" >
<props>
<!--如果出现Exception类型的异常,将跳转到error页面,error是视图名称,会被视图解析器解析-->
<prop key="java.lang.Exception">error</prop>
</props>
</property>
<!--exceptionAttribute设置一个属性名,将产生的异常信息在请求域中共享-->
<property name="exceptionAttribute" value="ex"></property>
</bean>
2、使用注解方式
@ControllerAdvice //将当前类标识为异常处理组件
public class ExceptionController {
@ExceptionHandler(value = {Exception.class})
public String testException(Exception e, Model model){
model.addAttribute("ex",e);
//跳转视图
return "error";
}
}