文章目录
一.数据响应
web开发中,数据响应分为两种形式。
1.页面跳转
-
直接返回字符串
-
返回ModelAndView
下面我们通过代码来分别展示这两种返回方式:
//success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h1>Success,${user}</h1>
</body>
</html>
@Controller
public class ControllerTest {
@RequestMapping("/run1")
public String run1(){
System.out.println("run1方法执行了");
return "success.jsp";//直接返回字符串
}
@RequestMapping("/run2")
//SpringMVC自动注入ModelAndView对象
public ModelAndView run2(ModelAndView modelAndView){
modelAndView.setViewName("success.jsp");//设置视图为success.jsp
//设置模型,相当于往域里存储数据
modelAndView.addObject("user","venture");
System.out.println("run2方法执行了");
return modelAndView;//返回modelAndView
}
}
访问/run1,服务器内部直接转发到success.jsp页面,输出结果如下
访问/run2,SpringMVC作为调用者会帮我们注入形参对象,而且ModelAndView也可以作为一个存储域(类似request存储域),用于存储数据。同理,我们也可以将Request对象作为形参,这样子就能拿到Request对象,就能往Request域里存数据。这里往ModelAndView域存储对象,输出结果如下:
2.回写数据
- 直接返回字符串
- 返回对象或集合
下面我们通过代码来分别展示这两种返回方式:
首先,我们使用原生servlet进行web开发给前台打印数据可以直接使用servlet为我们封装的Respose对象的write方法。现在,我们可以通过SpringMVC框架注入的response对象,使用response.getWriter().print(“hello world”) 回写数据,此时不需要视图跳转,业务方法返回值为void。如下
@RequestMapping("/run3")
public void run3(HttpServletResponse response) throws IOException {
System.out.println("run3方法执行了");
response.getWriter().write("hello");
}
访问/run3,浏览器输出结果如下
但是这样还是要用到Response对象,无疑加大了我们代码的复杂度。能不能让返回结果直接回写到前端页面上?但是通过上面的例子我们发现直接返回字符串是转发到目标字符串页面。为了区分返回值是用于页面跳转还是回写数据,SpringMVC提供了@ResponseBody1注解告知SpringMVC框架,方法返回的字符串不是用于跳转而是直接在http响应体中返回,达到数据回写的目地。
@RequestMapping("/run4")
@ResponseBody
public String run4() {
System.out.println("run4方法执行了");
return "Hello,Venture";
}
访问/run4,浏览器输出结果如下,可以看到输出了我们直接返回的字符串
但是更多情况下,我们回写前台的数据是对象或集合。例如返回json格式数据,我们可以使用jackson类似的数据对对象进行格式化后返回,但是这一搬砖式的操作又稍显令人乏味。所以,SpringMVC框架为我们提供了对象封装工具。
下面展示通过SpringMVC帮助我们对对象或集合进行json字符串的转换并回写,为处理器适配器配置消息转换参数, 指定使用jackson进行对象或集合的转换,因此需要在spring-mvc.xml中进行如下配置:
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
</bean>
</list>
</property>
</bean>
我们可以为请求映射处理器类RequestMappingHandlerAdapter的messageConverters属性注入Jackson消息转换器,他会自动将我们回写的对象转化为json格式。
另外,使用jacackson我们需要导入坐标
<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>
@RequestMapping("/run5")
@ResponseBody
public User run5(){
System.out.println("run5方法执行了");
User user = new User();
user.setName("zhangsan");
user.setAge(20);
return user;
}
访问/run5,浏览器以json格式输出数据
以上通过配置spring-mvc在方法上添加@ResponseBody就可以返回json格式的字符串,但是这样配置比较麻烦,配置的代码比较多, 因此,我们可以使用mvc的注解驱动代替上述配置。
<!--mvc的注解驱动-->
<mvc:annotation-driven/>
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。 使用<mvc:annotation-driven>
自动加载 RequestMappingHandlerMapping(处理映射器)和 RequestMappingHandlerAdapter( 处 理 适 配 器 ),可用<mvc:annotation-driven>
在Spring-xml.xml配置文件中使用替代注解处理器和适配器的配置。 同时使用<mvc:annotation-driven>
默认底层就会集成jackson进行对象或集合的json格式字符串的转换。
以后的SpringMVC项目中,建议都加上驱动注解
二.获得请求数据
1.请求参数类型
客户端请求参数的格式是:name=value&name=value…
服务器端要获得请求的参数,有时还需要进行数据的封装,SpringMVC可以接收如下类型的参数:
- 基本数据
- POJO2
- 数组
- 集合
2.获得基本数据类型参数
@RequestMapping("/run6")
@ResponseBody
public void run6(String username,int age){
System.out.println(username + "," + age);
}
访问/run6?username=tom&age=18 控制台输出结果如下:
tom,18
Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。另外,获得的参数默认都是字符串类型,SpringMVC会帮我们转换为指定的类型,如这里age就会被转换为整型。
3.获得POJO类型参数
@RequestMapping("/run7")
@ResponseBody
public void run7(User user){
System.out.println(user);
}
访问/run7?username=tom&age=18 控制台输出结果如下:
User{username=‘tom’, age=18}
User类定义了两个变量username和age,Controller中的业务方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配。
4.获得数组类型参数
@RequestMapping("/run8")
@ResponseBody
public void run8(String[] strs){
List<String> strings = Arrays.asList(strs);
System.out.println(strings);
}
访问/run8?strs=aaa&strs=bbb&strs=ccc 控制台输出如下:
[aaa, bbb, ccc]
Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配。
5.获得集合类型参数
有两种方式:
5.1 将集合作为POJO的属性。
获得集合参数时,要将集合参数包装到一个POJO中,一般这个POJO取名ValueObject,简写为VO
public class Vo {
private ArrayList<User> userList;
public Vo(ArrayList<User> userList) {
this.userList = userList;
}
public Vo() {
}
public ArrayList<User> getUserList() {
return userList;
}
public void setUserList(ArrayList<User> userList) {
this.userList = userList;
}
}
参数接收对象为VO对象,SpringMVC会帮我们映射并注入
@RequestMapping("/run9")
@ResponseBody
public void run9(Vo vo){
System.out.println(vo.getUserList());
}
我们创建一个表单模拟POST提交
<form action="${pageContext.request.contextPath}/run9" method="post">
<input type="text" name="userList[0].username"><br>
<input type="text" name="userList[0].age"><br>
<input type="text" name="userList[1].username"><br>
<input type="text" name="userList[1].age"><br>
<input type="submit" value="提交"><br>
</form>
访问/form.jsp 在表单中输入响应内容提交,控制台输出如下
[User{username=‘zhangsan’, age=18}, User{username=‘lisi’, age=20}]
userList[0]代表集合中的第一个元素,通过"."来确定集合的属性
5.2使用@RequestBody注解
当使用ajax提交时,可以指定contentType为json形式,那么在方法参数位置使用@RequestBody可以直接接收集合数据而无需使用POJO进行包装。。
@RequestMapping("/run10")
@ResponseBody
public void run10(@RequestBody List<User> userList){
System.out.println(userList);
}
创建一个ajax请求模拟提交
//ajax.jsp
<script>
//模拟数据
var userList = new Array();
userList.push({username: "zhangsan",age: "18"});
userList.push({username: "lisi",age: "20"});
$.ajax({
type: "POST",
url: "/run10",
data: JSON.stringify(userList),
contentType : 'application/json;charset=utf-8'
});
</script>
访问ajax.jsp,成功映射json数据,控制台输出如下:
[User{username=‘zhangsan’, age=18}, User{username=‘lisi’, age=20}]
6.静态资源放行3
将SpringMVC的前端控制器 DispatcherServlet的url-pattern为/后,若所访问的资源没有使用RequestMapping在容器内进行映射,则会找不到请求资源。例如访问静态资源会报404。原因是因为DispatcherServlet的url-pattern配置为/,代表对所有的资源都进行过滤操作。我们可以通过以下两种方式指定放行静态资源:
①开发对某些资源的访问权限,通过框架来处理:
在spring-mvc.xml配置文件中进行如下配置:
<mvc:resources mapping="/js/**" location="/js/"/>
放行js文件夹下的资源
②DispatcherServlet找不到请求的url映射的映射器,则交回给tomcat服务器处理
在spring-mvc.xml配置文件中进行如下配置:
<mvc:default-servlet-handler/>
tomcat容器的web.xml中有一个defaultServlet(用于处理静态资源),映射路径是"/“,我们自定义的web.xml最终相当于会与容器的web.xml合并,而自定义DispatchServlet一般也是使用”/",导致容器中的defaultServlet被覆盖,从而静态资源请求也会被发送到springmvc,springmvc会去找这个路径的映射器(相当于对应的Controller,这是找不到的),配置这个mvc:default-servlet-handler,就是在SpringMvc找不到映射路径后,再将其转给tomcat的defaultServlet,然后tomcat就可以正确解析静态资源路径。
7.请求数据乱码问题
tomcat8.5以上能解决get请求的数据乱码问题。当post请求时,中文数据会出现乱码,我们可以在web.xml中设置一个过滤器来进行编码的过滤。
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
8.参数绑定注解@RequestParam
当请求的参数名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示的绑定。
注解@RequestParam还有如下参数可以使用:
-
value:与请求参数名称
-
required:此在指定的请求参数是否必须包括,默认是true,提交时如果没有此参数则报错
-
defaultValue:当没有指定请求参数时,则使用指定的默认值赋值
@RequestMapping("/run11")
@ResponseBody
public void run11(@RequestParam(value="name",defaultValue = "王五") String username){
System.out.println(username);
}
访问/run11,控制台输出结果如下
王五
由于没有传参数,所以默认值为5
访问/run11?username=张三,控制台依旧输出王五
访问/run11?name=张三,控制台输出张三
通过观察我们可以发现,只有url参数的name与注解中value中设置的相对应,才视为有此参数。否则都会使用默认值。即使请求url中包含username,SpringMVC也不会帮我们映射到Controller方法的username参数中。所以这里Controller方法中的username只是作为一个形参,便于方法体的调用。
9.获得Restful风格的参数
Restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。主要用于客户端和服 器交互类的软件,基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。
Restful风格的请求是使用“url+请求方式”表示一次请求目的的,HTTP 协议里面四个表示操作方式的动词如下:
- GET:用于获取资源
- POST:用于新建资源
- PUT:用于更新资源
- DELETE:用于删除资源
@RequestMapping("/run12/{username}")
@ResponseBody
public void run12(@PathVariable(name = "username",required = true) String username){
System.out.println(username);
}
访问/run12/zhangsan 控制台输出如下:
zhangsan
在SpringMVC中可以使用占位符进行参数绑定。地址/run12/zhangsan可以写成 /run12/{username},占位符{username}对应的就是zhangsan的值。在业务方法中我们可以使用**@PathVariable注解**进行占位符的匹配获取工作。
10.自定义类型转换器
- SpringMVC 默认已经提供了一些常用的类型转换器,例如客户端提交的字符串转换成int型进行参数设置。
- 但是不是所有的数据类型都提供了转换器,没有提供的就需要自定义转换器.例如:日期类型的数据就需要自定义转换器。
自定义类型转换器的开发步骤:
① 定义转换器类实现Converter接口
package venture.study.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConverter implements Converter<String,Date> {
public Date convert(String source) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = format.parse(source);
return date;
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
② 在配置文件中声明转换器
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="venture.study.converter.DateConverter"></bean>
</set>
</property>
</bean>
③ 在<mvc:annotion-driven>
中引用转换器
<mvc:annotation-driven conversion-service="conversionService"/>
定义控制器
@RequestMapping("/run1")
@ResponseBody
public void run1(Date dt){
System.out.println(dt);
}
访问run1?dt=2018-2-3,控制台输出结果如下
Sat Feb 03 00:00:00 CST 2018
11. 获得请求头
11.1 @RequestHeader
使用@RequestHeader可以获得请求头信息,相当于web阶段学习的request.getHeader(name)
@RequestHeader注解的属性如下:
- value:请求头的名称
- required:是否必须携带此请求头
@RequestMapping("/run14")
@ResponseBody
public void run14(@RequestHeader(value="accept",required = false) String accept){
System.out.println(accept);
}
访问/run14,控制台输出结果如下:
text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
11.2 @CookieValue
使用@CookieValue可以获得指定Cookie的值
@CookieValue注解的属性如下:
-
value:指定cookie的名称
-
required:是否必须携带此cookie
@RequestMapping("/run15")
@ResponseBody
public void run15(@CookieValue(value = "JSESSIONID",required = false) String jSESSIONID){
System.out.println(jSESSIONID);
}
访问/run15,给定cookie的键,控制台直接输出cookie的value
D805355FC2E6AB77466C66CFB57634F2
11.2 @CookieValue
使用@CookieValue可以获得指定Cookie的值
@CookieValue注解的属性如下:
-
value:指定cookie的名称
-
required:是否必须携带此cookie
@RequestMapping("/run15")
@ResponseBody
public void run15(@CookieValue(value = "JSESSIONID",required = false) String jSESSIONID){
System.out.println(jSESSIONID);
}
访问/run15,给定cookie的键,控制台直接输出cookie的value
D805355FC2E6AB77466C66CFB57634F2