1.请求
1.请求参数
SpringMVC将传递的参数封装到处理器方法的形参中,达到快速访问参数的目的
1.普通类型参数传参
page.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h1>请求参数测试页面</h1>
</body>
</html>
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中使用的完全相同,差异之处在于处理器的类由Spring提供--><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></filter><filter-mapping><filter-name>CharacterEncodingFilter</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*:spring-mvc.xml</param-value></init-param></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>
spring-mvc.xml
<context:component-scan base-package="com"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan>
新建com.controller.UserController类
参数名与处理器方法形参名保持一致
//http://localhost/requestParam1?name=ljb//http://localhost/requestParam1?name=ljb&age=20@RequestMapping("/requestParam1")public String requestParam1(String name,int age){System.out.println(name+","+age);return "page.jsp";}
@RequestParam 的使用
类型: 形参注解
位置:处理器类中的方法形参前方
作用:绑定请求参数与对应处理方法形参间的关系
//http://localhost/requestParam2?userName=ljb@RequestMapping("/requestParam2")public String requestParam2(@RequestParam(value = "userName",required = true) String name){System.out.println(name);return "page.jsp";}
2.POJO类型参数传参
当POJO中使用简单类型属性时, 参数名称与POJO类属性名保持一致
新建domain.User
package com.domain;public class User {private String name;private Integer age;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
//http://localhost/requestParam3?name=ljb&age=20@RequestMapping("/requestParam3")public String requestParam3(User user){System.out.println(user);return "page.jsp";}
当POJO类型属性与其他形参出现同名问题时,将被同时赋值
//http://localhost/requestParam4?name=ljb&age=20@RequestMapping("/requestParam4")public String requestParam4(User user,int age){System.out.println("user="+user+",age="+age);return "page.jsp";}
建议使用@RequestParam注解进行区分
当POJO中出现对象属性时,参数名称与对象层次结构名称保持一致
新建Address类写入province,city,address与对应getter,setter,tostring
在User类加入Address与其getter,setter等
//http://localhost/requestParam5?address.city=beijing@RequestMapping("/requestParam5")public String requestParam5(User user){System.out.println(user.getAddress().getCity());return "page.jsp";}
当POJO中使用简单类型属性时,参数名称与POJO类属性名保持一致
private List<String> nick;public List<String> getNick() {return nick;}public void setNick(List<String> nick) {this.nick = nick;}
+toString...
//http://localhost/requestParam6?nick=jock1&nick=jockme&nick=ljb@RequestMapping("/requestParam6")public String requestParam6(User user){System.out.println(user);return "page.jsp";}
当POJO中出现List,保存对象数据,参数名称与对象层次结构名称保持一致,使用数组格式描述集合中对象的位置
添加private List<Address> addresses;与其对应方法
//http://localhost/requestParam7?addresses[0].city=beijing&addresses[1].province=gansu@RequestMapping("/requestParam7")public String requestParam7(User user){System.out.println(user.getAddresses());return "page.jsp";}
当POJO中出现Map,保存对象数据,参数名称与对象层次结构名称保持一致,使用映射格式描述集合中对象的位置
package com.domain;import java.util.List;
import java.util.Map;public class User {private String name;private Integer age;private Address address;private List<String> nick;private List<Address> addresses;private Map<String,Address> addressMap;public Map<String, Address> getAddressMap() {return addressMap;}public void setAddressMap(Map<String, Address> addressMap) {this.addressMap = addressMap;}public List<Address> getAddresses() {return addresses;}public void setAddresses(List<Address> addresses) {this.addresses = addresses;}public List<String> getNick() {return nick;}public void setNick(List<String> nick) {this.nick = nick;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +", address=" + address +", nick=" + nick +", addresses=" + addresses +", addressMap=" + addressMap +'}';}
}
//http://localhost/requestParam8?addressMap['job'].city=beijing&addressMap['home'].province=gansu@RequestMapping("/requestParam8")public String requestParam8(User user){System.out.println(user.getAddressMap());return "page.jsp";}
//{home=Address{province='gansu', city='null', address='null'}, job=Address{province='null', city='beijing', address='null'}}
3.数组与集合类型参数传参
数组类型传参
请求参数名与处理器方法形参名保持一致,且请求参数数量> 1个
//http://localhost/requestParam9?nick=jockme&nick=ljb@RequestMapping("/requestParam9")public String requestParam9(String[] nick){System.out.println(nick[0]+","+nick[1]);return "page.jsp";}
集合类型传参
保存简单类型数据,请求参数名与处理器方法形参名保持一致,且请求参数数量> 1个
//http://localhost/requestParam10?nick=jockme&nick=ljb@RequestMapping("/requestParam10")public String requestParam10(@RequestParam("nick") List<String> nick){System.out.println(nick);return "page.jsp";}
//[jockme, ljb]
注意: SpringMVC默认将List作为对象处理,赋值前先创建对象,然后将nick作为对象的属性进行处理。由于List是接口,无法创建对象,报无法找到构造方法异常;修复类型为可创建对象的ArrayList类型后,对象可以创建,但没有nick属性,因此数据为空。此时需要告知SpringMVC的处理器nick是一组数据,而不是一个单一数据。通过@RequestParam注解,将数量大于1个names参数打包成参数数组后, SpringMVC才能识别该数据格式,并判定形参类型是否为数组或集合,并按数组或集合对象的形式操作数据
2.类型转换器
SpringMVC对接收的数据进行自动类型转换,该工作通过Converter接口实现
声明自定义的转换格式并覆盖系统转换格式
<context:component-scan base-package="com"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan><!--5.启用自定义Converter--><mvc:annotation-driven conversion-service="conversionService"/><!--1.设定格式类型Converter,注册为Bean,受SpringMVC管理--><bean id="conversionService"class="org.springframework.format.support.FormattingConversionServiceFactoryBean"><!--2.自定义Converter格式类型设定,该设定使用的是同类型覆盖的思想--><property name="formatters"><!--3.使用set保障相同类型的转换器仅保留一个,避免冲突--><set><!--4.设置具体的格式类型--><bean class="org.springframework.format.datetime.DateFormatter"><!--5.类型规则--><property name="pattern" value="yyyy-MM-dd"/></bean></set></property></bean>
//http://localhost/requestParam11?date=2023-11-23@RequestMapping("/requestParam11")public String requestParam11(Date date){System.out.println(date);return "page.jsp";}
日期类型格式转换(简化版)
名称: @DateTimeFormat
类型: 形参注解、成员变量注解
位置:形参前面 或 成员变量上方
作用:为当前参数或变量指定类型转换规则
<context:component-scan base-package="com"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan><mvc:annotation-driven/>
//http://localhost/requestParam11?date=2023-11-23@RequestMapping("/requestParam11")public String requestParam11(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date){System.out.println(date);return "page.jsp";}
3.请求映射
@RequestMapping
当定义在方法上
类型: 方法注解
位置:处理器类中的方法定义上方
作用:绑定请求地址与对应处理方法间的关系
//http://localhost/requestURL2
@Controller
public class UserController {@RequestMapping("/requestURL2")public String requestURL2() {return "page.jsp";}
}
当定义在类上
类型: 类注解
位置:处理器类定义上方
作用:为当前处理器中所有方法设定公共的访问路径前缀
//http://localhost/user/requestURL2
@Controller
@RequestMapping("/user")
public class UserController {@RequestMapping("/requestURL2")public String requestURL2() {return "page.jsp";}
}
注意:如果加了/user要求所有的页面都在user目录下
常用属性
@RequestMapping(value="/requestURL3", //设定请求路径,与path属性、 value属性相同method = RequestMethod.GET, //设定请求方式params = "name", //设定请求参数条件headers = "content-type=text/*", //设定请求消息头条件consumes = "text/*", //用于指定可以接收的请求正文类型(MIME类型)produces = "text/*" //用于指定可以生成的响应正文类型(MIME类型)
)
public String requestURL3() {return "/page.jsp";
}
2.响应
响应方式
1.页面跳转
当处理器方法的返回值类型为String类型,即可通过具体的返回值设置访问的页面
转发(默认)
@RequestMapping("/showPage1")
public String showPage1() {System.out.println("user mvc controller is running ...");return "forward:page.jsp";
}
重定向
@RequestMapping("/showPage2")
public String showPage2() {
System.out.println("user mvc controller is running ...");
return "redirect:page.jsp";
}
注意:页面访问地址中所携带的 /
重定向地址栏发生了变化
页面访问快捷设定
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/page/"/><property name="suffix" value=".jsp"/>
</bean>
public String showPage3() {return "page";
}
如果未设定了返回值,使用void类型,则默认使用访问路径作页面地址的前缀后缀
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/page/"/><property name="suffix" value=".jsp"/></bean>
//最简页面配置方式,使用访问路径作为页面名称,省略返回值
@RequestMapping("/showPage5")
public void showPage5() {System.out.println("user mvc controller is running ...");
}
2.带数据的页面跳转
方式一:使用HttpServletRequest类型形参进行数据传递
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h1>页面跳转测试中.../WEB-INF/page/page.jsp</h1>
info:${name}
</body>
</html>
@RequestMapping("/showPageAndData1")
public String showPageAndData1(HttpServletRequest request) {request.setAttribute("name","ljb");return "page";
}
方式二:使用Model类型形参进行数据传递
<body>
<h1>页面跳转测试中.../WEB-INF/page/page.jsp</h1>
info:${name}<br>
book的name:${book.name}<br>
book的price:${book.price}<br>
</body>
package com.domain;public class Book {private String name;private Double price;public String getName() {return name;}public void setName(String name) {this.name = name;}public Double getPrice() {return price;}public void setPrice(Double price) {this.price = price;}@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", price=" + price +'}';}
}
@RequestMapping("/showPageAndData2")
public String showPageAndData2(Model model) {model.addAttribute("name","ljb");Book book = new Book();book.setName("SpringMVC入门实战");book.setPrice(66.6d);model.addAttribute("book",book);return "page";
}
方法三:使用ModelAndView类型形参进行数据传递,将该对象作为返回值传递给调用者
//使用ModelAndView形参传递参数,该对象还封装了页面信息
@RequestMapping("/showPageAndData3")
public ModelAndView showPageAndData3(ModelAndView modelAndView) {//ModelAndView mav = new ModelAndView(); 替换形参中的参数Book book = new Book();book.setName("SpringMVC入门案例");book.setPrice(66.66d);//添加数据的方式,key对valuemodelAndView.addObject("book",book);//添加数据的方式,key对valuemodelAndView.addObject("name","Jockme");//设置页面的方式,该方法最后一次执行的结果生效modelAndView.setViewName("page");//返回值设定成ModelAndView对象return modelAndView;
}
附:使用ModelAndView类型形参进行数据传递,将该对象作为返回值传递给调用者
@RequestMapping("/showPageAndData4")public ModelAndView showPageAndData4 (ModelAndView modelAndView){modelAndView.setViewName("forward:WEB-INF/page/page.jsp");return modelAndView;}@RequestMapping("/showPageAndData5")public ModelAndView showPageAndData5(ModelAndView modelAndView){modelAndView.setViewName("redirect:page.jsp");return modelAndView;}
3.返回数据
方式一:使用response对象完成数据返回
@RequestMapping("/showData1")public void showData1(HttpServletResponse response) throws IOException {response.getWriter().write("message");}
方式二:使用@ResponseBody
@ResponseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,可用于将方法的返回值直接作为HTTP响应的内容返回给客户端,通常用来返回JSON数据或者是XML数据
@RequestMapping("/showData2")@ResponseBodypublic String showData2(){return "message";}
4.返回json数据
方法一:基于response返回数据的简化格式,返回JSON数据
导入json坐标
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com</groupId><artifactId>MVCresponse</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.1.19.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.9.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.22</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.16</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.13</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.7</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency><!--servlet3.1规范的坐标--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><!--jsp坐标--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.1</version><scope>provided</scope></dependency><!--spring web坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.1.9.RELEASE</version></dependency><!--springmvc坐标--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.9.RELEASE</version></dependency><!--json相关坐标3个--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.9.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.9.0</version></dependency></dependencies><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><!--构建--><build><!--设置插件--><plugins><!--具体的插件配置--><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.1</version><configuration><port>80</port><path>/</path></configuration></plugin></plugins></build></project>
//使用jackson进行json数据格式转化
@RequestMapping("/showData3")
@ResponseBody
public String showData3() throws JsonProcessingException {Book book = new Book();book.setName("SpringMVC入门案例");book.setPrice(66.66d);ObjectMapper om = new ObjectMapper();return om.writeValueAsString(book);
}
方法二:使用SpringMVC提供的消息类型转换器将对象数据自动转换为JSON数据
//使用SpringMVC注解驱动,对标注@ResponseBody注解的控制器方法进行结果转换,由于返回值为引用类型,自动调用jackson提供的类型转换器进行格式转换
@RequestMapping("/showData4")
@ResponseBody
public Book showData4() {Book book = new Book();book.setName("SpringMVC入门案例");book.setPrice(66.66d);return book;
}
需手工添加信息类型转换器或添加注解驱动简化配置
<mvc:annotation-driven/>
同时解决了乱码问题
方法三:使用SpringMVC提供的消息类型转换器将集合数据自动转换为JSON数据
@RequestMapping("/showData5")@ResponseBodypublic List showData5(){Book book1 = new Book();book1.setName("SpringMVC入门案例");book1.setPrice(66.66d);Book book2 = new Book();book2.setName("SpringMVC入门案例");book2.setPrice(66.66d);ArrayList al = new ArrayList();al.add(book1);al.add(book2);return al;}
3.Servlet相关接口替换方案
1.SpringMVC提供访问原始Servlet接口API的功能,通过形参声明即可
package com.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;@Controller
public class UserController {@RequestMapping("/servletApi")public String servletApi(HttpServletRequest request, HttpServletResponse response, HttpSession session){System.out.println(request);System.out.println(response);System.out.println(session);return "page";}
}
2.Head数据获取
名称: @RequestHeader
类型: 形参注解
位置:处理器类中的方法形参前方
作用:绑定请求头数据与对应处理方法形参间的关系
先开启注解驱动
<mvc:annotation-driven/>
@RequestMapping("/headApi")public String headApi(@RequestHeader("Accept-Encoding") String headMsg){System.out.println(headMsg);System.out.println();return "page";}
3.cookie数据获取
名称: @CookieValue
类型: 形参注解
位置:处理器类中的方法形参前方
作用:绑定请求Cookie数据与对应处理方法形参间的关系
@RequestMapping("/cookieApi")public String cookieApi(@CookieValue("JSESSIONID") String jsessionid){System.out.println(jsessionid);return "page";}
4.Session 数据获取
名称: @SessionAttribute
类型: 形参注解
位置:处理器类中的方法形参前方
作用:绑定请求Session数据与对应处理方法形参间的关系
//http://localhost/setSessionData
@RequestMapping("/setSessionData")public String serSessionData(HttpSession session){session.setAttribute("name","ljb");return "page";}
//http://localhost/sessionApi@RequestMapping("/sessionApi")public String sessionApi(@SessionAttribute("name") String name){System.out.println(name);return "page";}
5.Session数据设置
名称: @SessionAttributes
类型: 类注解
位置:处理器类上方
作用:声明放入session范围的变量名称,适用于Model类型数据传参
@Controller
@SessionAttributes(names={"name"})
public class ServletController {@RequestMapping("/sessionApi")public String sessionApi(@SessionAttribute("name") String name,@SessionAttribute("age") int age,@SessionAttribute("gender") String gender){System.out.println(name);System.out.println(age);System.out.println(gender);return "page";}@RequestMapping("/setSessionData2")public String serSessionData2(Model model){model.addAttribute("age",20);model.addAttribute("gender","男");return "page";}
}
因为没有name所以还要先运行一次setSessionData然后setSessionData2然后sessionApi
注解式参数数据封装底层原理
数据的来源不同,对应的处理策略要进行区分
Head
Cookie
Session
SpringMVC使用策略模式进行处理分发
顶层接口:HandlerMethodArgumentResolver
实现类: ……