SpringMVC的请求和响应


1 SpringMVC的数据响应

1.1 页面跳转

1)返回字符串:发、重定向两种

2)通过ModelAndView对象返回

@Controller //将该类放到spring容器中
public class UserController {
// 返回字符串
@RequestMapping("/request") //请求映射关系,当访问/quick时自动跳转到该方法
public String save() {
return "/success.jsp"; //需要跳转的视图,即jsp等文件
}

// 通过ModelAndView对象返回
//方式1:手动new modelAndView
@RequestMapping("/quick2") //请求映射关系,当访问/quick时自动跳转到该方法
public ModelAndView save2() {
ModelAndView modelAndView = new ModelAndView();
//设置Model数据,即存数据到request域中
modelAndView.addObject("name", "张无忌"); //在success.jsp使用EL表达式可获取该值:${name}
//设置视图名称,即跳转的页面
modelAndView.setViewName("success.jsp");
return modelAndView;
}

//方式2:spring解析方法时自动注入modelAndView提供使用
@RequestMapping("/quick3") //请求映射关系,当访问/quick时自动跳转到该方法
public ModelAndView save3(ModelAndView modelAndView) {
//设置Model数据,即存数据到request域中
modelAndView.addObject("name", "郭靖"); //在success.jsp使用EL表达式可获取该值:${name}
//设置视图名称,即跳转的页面
modelAndView.setViewName("success.jsp");
return modelAndView;
}

//方式3:视图数据拆分
@RequestMapping("/quick4") //请求映射关系,当访问/quick时自动跳转到该方法
public String save4(Model model) {
model.addAttribute("name", "杨过");
return "success.jsp";
}

// 使用原生request
@RequestMapping("/quick5") //请求映射关系,当访问/quick时自动跳转到该方法
public String save5(HttpServletRequest request) {
request.setAttribute("name","孙悟空");
return "success.jsp";
}
}

1.2 回写数据

1)普通回写

//通过response回写
@RequestMapping("/quick6") //请求映射关系,当访问/quick时自动跳转到该方法
public void save6(HttpServletResponse response) throws IOException {
response.getWriter().write("hello mvc");
}

//使用注解返回字符串回写
@RequestMapping("/quick7")
@ResponseBody //通过@ResponseBody注解告知SpringMVC框架,方法返回的字符串不是跳转是直接在http响应体中返回。
public String save7() {
return "hello,spring mvc";
}

2)返回对象或集合

通过SpringMVC帮助我们对对象或集合进行json字符串的换并回写,为处理器适配器配置消息转换参数,指定使用jackson进行对象或集合的转换,因此需要在spring-mvc.xml中进行如下配置:

SpringMVC的请求和响应_spring

SpringMVC的请求和响应_intellij-idea_02

<!--    配置处理器映射器-->
<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>
//返回json格式
@RequestMapping("/quick8") //请求映射关系,当访问/quick时自动跳转到该方法
@ResponseBody
public User save8() {
User user = new User("zhangsan", "female", 22);
return user;
}

在方法上添加@ResponseBody就可以返回json格式的字符串,可以使用mvc的注解驱动代替上述配置。

<!--mvc的注解驱动-->
<mvc:annotation-driven/>

在 SpringMVC 的各个组件中,​处理器映射器、处理器适配器、视图解析器​称为 SpringMVC 的三大组件。

使用< mvc:annotation-driven >自动加载 RequestMappingHandlerMapping(处理映射器)和RequestMappingHandlerAdapter( 处 理 适 配 器 ),可用在Spring-xml.xml配置文件中使用
< mvc:annotation-driven >替代注解处理器和适配器的配置。同时使用< mvc:annotation-driven >默认底层就会集成jackson进行对象或集合的json格式字符串的换。

导入mvc:命名空间:

SpringMVC的请求和响应_springmvc_03SpringMVC的请求和响应_mvc_04

2 SpringMVC请求

2.1 获得请求参数

2.1.1 基本类型参数

Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。

//请求地址:http://localhost:8080/SpringIoC_03_MVC_war_exploded/test1?name=zhangsan&age=22
@RequestMapping("/test1")
@ResponseBody
public void test1(String name,int age){
System.out.println(name+" "+age);
}

2.1.2 POJO类型参数

Controller中的业务方法的POJO(实体)参数的属性名与请求参数的name一致,参数值会自动映射匹配

private String name;
private String gender;
private int age;
public void setName(String name) {
this.name = name;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setAge(int age) {
this.age = age;
}

//请求地址:http://localhost:8080/SpringIoC_03_MVC_war_exploded/test2?name=zhangsan&gender=female&age=22
@RequestMapping("/test2")
@ResponseBody
public void test2(User user){
System.out.println(user);
}

2.1.3 数组类型参数

Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配。

//请求地址:http://localhost:8080/SpringIoC_03_MVC_war_exploded/test3?arr=1&arr=2&arr=3
@RequestMapping("/test3")
@ResponseBody
public void test3(String[] arr){
System.out.println(Arrays.asList(arr));
}

2.1.4 集合类型参数

当使用​ajax提交​时,可以指定contentType为json形式,那么在方法参数位置使用 ​@RequestBody​可以直接接收集合数据而无需使用POJO进行包装。

前端发送Ajax异步请求:

<script>
//ajax提交
var list = new Array();
list.push({name: "张三", gender:"男",age: 20})
list.push({name: "李四", gender:"男",age: 22})
$.ajax({
type:"POST",
url:"http://localhost:8080/SpringIoC_03_MVC_war_exploded/test5",
data:JSON.stringify(list),
contentType:'application/json;charset=utf-8'
});
</script>

后端封装数据:

@RequestMapping("/test5")
@ResponseBody
public void test4(@RequestBody List<User> list){ //使用@RequestBody注解
System.out.println(list);
}

注意:通过谷歌开发者工具抓包发现,没有加载到jquery文件,原因是SpringMVC的前端控制器
DispatcherServlet的url-pattern配置的是/,代表对所有的资源都进行过滤操作,我们可以通过以下两种方式指定放行静态资源:

<!--开放静态资源访问-->
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:default-servlet-handler/>

2.2 配置全局乱码过滤器

当post请求时,数据会出现乱码,我们可以在web.xml中设置一个过滤器来进行编码的过滤。

<!--配置全局过滤filter-->
<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>

2.3 参数绑定注解@requestParam

当请求的参数名称与Controller的业务方法参数名称不一致时,就需要通过@RequestParam注解显示的绑定。

注解@RequestParam还有如下参数可以使用:
value:与请求参数名称
required:此在指定的请求参数是否必须包括,默认是true,提交时如果没有此参数则报错
defaultValue:当没有指定请求参数时,则使用指定的默认值赋值
@RequestMapping("/test6")
@ResponseBody
public void test6(@RequestParam(value = "name",required = false,defaultValue = "张无忌") String userName){ //表单名字与参数名不一样时,使用注解将表单名字映射到参数名
System.out.println(userName);
}

2.4 获得Restful风格的参数

Restful风格的请求是使用“url+请求方式”表示一次请求目的的,HTTP 协议里面四个表示操作方式的动词如下:
GET:用于获取资源
POST:用于新建资源
PUT:用于更新资源
DELETE:用于删除资源
//    请求地址:http://localhost:8080/SpringIoC_03_MVC_war_exploded/test7/zhangwuji
@RequestMapping("/test7/{username}")
@ResponseBody
public void test7(@PathVariable(value = "username") String username){
System.out.println(username);
}

2.5 自定义类型转换器

自定义类型换器的开发步骤:
① 定义转换器类实现Converter接口

public class DateConverter implements Converter<String, Date> {
public Date convert(String dateStr){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date parse = null;
try {
parse = simpleDateFormat.parse(dateStr);
return parse;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}

② 在配置文件中声明换器
③ 在中引用转换器

<!--    声明转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="lifeilin.converter.DateConverter"></bean>
</list>
</property>
</bean>

<!-- mvc的注解驱动-->
<mvc:annotation-driven conversion-service="conversionService"/>

2.6 获取请求头

SpringMVC的请求和响应_java_05

@RequestMapping("/test9")
@ResponseBody
public void test9(@RequestHeader(value = "User-Agent", required = false) String user_agent) {
System.out.println(user_agent);
//Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36
}

@RequestMapping("/test10")
@ResponseBody
public void test10(@CookieValue(value = "JSESSIONID") String jsessionid) {
System.out.println(jsessionid);
//11A3DBD3B27CAF5CBC738D63A51CC974
}

2.7 文件上传

1)客户端实现:

SpringMVC的请求和响应_spring_06

2)文件上传实现:

① 导入fileupload和io坐标

<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.2</version>
</dependency>

② 配置文件上传解析器(spring-mvc.xml)

<!--    配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 上传文件总大小-->
<property name="maxUploadSize" value="5242800"/>
<!-- 上传单个文件的大小-->
<property name="maxUploadSizePerFile" value="5242800"/>
<!-- 上传文件编码类型-->
<property name="defaultEncoding" value="UTF-8"/>
</bean>

③ 编写文件上传代码

@RequestMapping("/test11")
@ResponseBody
public void test11(String name, MultipartFile file) throws IOException { //参数名称与表单的名称一致
System.out.println(name);
//获取上传文件名称
String filename = file.getOriginalFilename();
file.transferTo(new File("D:\\" + filename));
}

3)多文件上传

多文件上传可以使用多个表单进行上传,但是如果客户端多个表单的名字相同,则在服务端就可以使用数组接收多文件上传:

客户端:

<form action="${pageContext.request.contextPath}/test12" method="post" enctype="multipart/form-data">
文件名称:<input type="text" name="name"><br>
文件:<input type="file" name="file"><br>
文件:<input type="file" name="file"><br>
文件:<input type="file" name="file"><br>
<input type="submit" value="提交">
</form>

服务端:

@RequestMapping("/test12")
@ResponseBody
public void test12(String name, MultipartFile[] file) throws IOException { //参数名称与表单的名称一致
System.out.println(name);
//获取上传文件名称
for (MultipartFile multipartFile : file) {
String originalFilename = multipartFile.getOriginalFilename();//每个文件名
multipartFile.transferTo(new File("D:\\" + originalFilename));
}
}