SpringMVC —— 响应和请求处理
一、前言
本文需要导入的坐标:(SpringMVC框架)
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.9.RELEASE</version></dependency>
请先阅读上一篇:SpringMVC —— Spring集成web环境和SpringMVC快速入门-CSDN博客
二、SpringMVC响应处理
(1)页面跳转测试
1.准备工作
首先需要准备dao层和service层的接口及其实现类:
dao层:
public interface UserDao {public void save();
}
public class UserDaoImpl implements UserDao {@Overridepublic void save() {System.out.println("save running...");}
}
service层:
public interface UserService {public void save();
}
public class UserServiceImpl implements UserService {private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}@Overridepublic void save() {userDao.save();}
}
同时需要依赖注入到app配置文件:
<bean id="userDao" class="com.yds.dao.impl.UserDaoImpl"></bean><bean id="userService" class="com.yds.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property></bean>
2.字符串转发
首先准备一个跳转的目标JSP文件success:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head><title>Title</title>
</head>
<body>
<h1>success</h1>
</body>
</html>
这里我们摒弃掉传统的Servlet类,使用注解来创建高度封装的Controller类:
我们希望跳转到webapp中的jsp软件包中的success.jsp文件,可以直接return字符串(上一篇末尾提到的)
@Controller
@RequestMapping("/user")
public class UserController {@RequestMapping(value = "/quick")//返回字符串public String save() {System.out.println("Controller save running...");//在配置内部资源视图解析器后直接使用success:return "/jsp/success.jsp";}
}
网页和控制台效果如下:
但是每次都需要写前后缀很麻烦,所以我们这里使用配置内部资源视图解析器来统一添加前后缀:
<!-- 配置内部资源视图解析器(自动指定前后缀)--><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/jsp/"></property><property name="suffix" value=".jsp"></property></bean>
所以我们可以将代码优化为:
@RequestMapping(value = "/quick")//返回字符串public String save() {System.out.println("Controller save running...");//在配置内部资源视图解析器后直接使用success:return "/jsp/success.jsp";}
效果当然也是一样的,这里就不赘述了。
3.返回ModelAndView对象
这里达到的效果和字符串转发是一样的,但是引入了ModelAndView类,SpringMVC框架允许通过返回ModelAndView类的对象来进行跳转操作。
@RequestMapping(value = "/quick2")//返回ModelAndView对象public ModelAndView save2() {//Model:模型 作用:封装数据//View:视图:展示数据ModelAndView modelAndView = new ModelAndView();//设置模型数据modelAndView.addObject("username", "yds");//设置视图名称modelAndView.setViewName("success");return modelAndView;}
这里我们将yds存储在模型中,把JSP文件储存到视图中,为了测试模型数据是否存储成功,我们需要改动JSP文件,添加EL表达式:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head><title>Title</title>
</head>
<body>
<h1>success ${username}</h1>
</body>
</html>
测试结果如下:
4.使用形参来创建对象
同样使用ModelAndView的办法,唯一的改动就是创建对象可以在形参中创建,这是SpringMVC框架提供的简化办法,也是后面最常用的方法。
@RequestMapping(value = "/quick3")//从形参创建一个ModelAndView对象,然后设置数据、设置视图public ModelAndView save3(ModelAndView modelAndView) {modelAndView.addObject("username", "xzt");modelAndView.setViewName("success");return modelAndView;}
当然是一样的效果:
5.混合使用
@RequestMapping(value = "/quick4")//混合使用也可以public String save4(Model model) {model.addAttribute("username", "印东升");return "success";}
这里我们不再设置视图,只设置模型中的数据,然后使用字符串转发,这样的方式也可以成功运行:
6.使用request这样的ServletAPI
@RequestMapping(value = "/quick5")//不常用,使用了servlet的东西(尽量使用mvc框架提供的东西)public String save5(HttpServletRequest request) {request.setAttribute("username", "熊梓彤");return "success";}
注意:这是以前Servlet设置文本域的方式,尽量使用Springmvc框架提供的东西,所以少用。
当然效果是一样的:
(2)回写数据测试
1.使用Servlet的API回写数据
@RequestMapping(value = "/quick6")//和quick5类似,回显数据public void save6(HttpServletResponse response) throws IOException {response.getWriter().print("hello yds");}
效果如下:
2.使用注解@ResponseBody
使用@ResponseBody注解,告诉Springmvc框架,不进行视图跳转,直接进行数据响应,这一个方式很重要!!!后面基本上都是使用这个方式来进行数据回写。
@RequestMapping(value = "/quick7")//使用@ResponseBody注解,告诉mvc框架,不进行视图跳转,直接进行数据响应//重要!!!@ResponseBodypublic String save7() throws IOException {return "hello xzt";}
效果如下:
3.回写Json格式字符串
这里我们手写Json格式,当然是最复杂的方式了,这里仅供测试:
@RequestMapping(value = "/quick8")//回写Json格式字符串@ResponseBodypublic String save8() throws IOException {return "{\"username\":\"yds\",\"age\":20}";}
效果如下:
4.使用json的转换工具
这里首先需要添加工具坐标,这里我们使用Jackon
<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(value = "/quick9")//使用json的转换工具将对象转换成json格式字符串再返回@ResponseBodypublic String save9() throws IOException {User user = new User();user.setName("yds");user.setAge("20");//使用json的转换工具将对象转换成json格式字符串再返回ObjectMapper objectMapper = new ObjectMapper();String json = objectMapper.writeValueAsString(user);return json;}
效果如下:
5.SpringMVC自动转换
要想使用自动转换,首先需要在mvc配置中配置处理器映射器:(也可以用下面的驱动代替,原理是注解@ResponseBody中允许返回Json格式的字符串,使用只要加载处理适配器的驱动就可以实现自动转换)
<!-- 配置处理器映射器(可以由下面的驱动替代)--><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><mvc:annotation-driven/>
@RequestMapping(value = "/quick10")//mvc将User自动转换为Json格式的字符串(需要在xml中配置)@ResponseBodypublic User save10() throws IOException {User user = new User();user.setName("印东升");user.setAge("88");return user;}
效果如下:
三、SpringMVC请求处理
(1)请求处理
1.获得基本数据类型
//获得基本数据类型@RequestMapping(value = "/quick11")@ResponseBody//还是要写public void save11(String username, int age) throws IOException {System.out.println(username);System.out.println(age);}
注意:这里尽管是处理请求,返回值也是void,但是仍然要写 @ResponseBody来标志不是页面跳转,否则响应体为void,会报404。
拼接参数username和age:
效果如下:
2.获得Pojo类型
这里框架会自动封装参数到Pojo中:
//获得pojo类型 会自动封装@RequestMapping(value = "/quick12")@ResponseBodypublic void save12(User user) throws IOException {System.out.println(user);}
效果如下:
3.获得数组类型
注意:这里的参数必须和形参相同,否则会被判定为空
@RequestMapping(value = "/quick13")@ResponseBodypublic void save13(String[] strs) throws IOException {System.out.println(Arrays.toString(strs));}
效果如下:
4.获得集合类型(放pojo中)
获得集合类型有两种方式,第一种需要使用包装对象来实现转换,原因是请求不能是泛型,所以我们这里创建一个VO(valueObject)包装类,用来包装集合,最后只需要将请求参数设置为包装对象即可:
public class VO {private List<User> userList;public List<User> getUserList() {return userList;}public void setUserList(List<User> userList) {this.userList = userList;}@Overridepublic String toString() {return "VO{" +"userList=" + userList +'}';}
}
@RequestMapping(value = "/quick14")@ResponseBodypublic void save14(VO vo) throws IOException {System.out.println(vo);}
这里为了测试,我们创建一个JSP文件,并且创建一个表单:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %><html>
<head><title>Title</title>
</head>
<body><form action="${pageContext.request.contextPath}/user2/quick14" method="post">
<%-- 表明是第几个User对象的username age--%><input type="text" name="userList[0].name"><br/><input type="text" name="userList[0].age"><br/><input type="text" name="userList[1].name"><br/><input type="text" name="userList[1].age"><br/><input type="submit"></form>
</body>
</html>
输入后结果如下:
5.获得集合类型(直接转化为json)
这里我们使用注解@RequestBody,可以直接接收集合数据,不需要再包装了。
//获得集合类型(直接转化为json)@RequestMapping(value = "/quick15")@ResponseBodypublic void save15(@RequestBody List<User> userList) throws IOException {System.out.println(userList);}
由于是直接转化为Json,使用这里我们需要写一个ajax文件来进行测试:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %><html>
<head><title>Title</title><script src="${pageContext.request.contextPath}/js/jquery.js"></script><script>var userList = new Array();userList.push({name:"印东升",age:20});userList.push({name:"zy",age:19});$.ajax({type:"POST",url:"${pageContext.request.contextPath}/user2/quick15",data:JSON.stringify(userList),contentType:"application/json;charset=utf-8"});</script>
</head>
<body></body>
</html>
注意:这里ajax无法访问jquery.js,因为是静态资源,所以需要使用以下任意一种方式来开启静态资源的访问。
<!-- 开放(静态)资源的访问-->
<mvc:resources mapping="/js/**" location="/js/"/><!-- 让tomcat去找静态资源-->
<mvc:default-servlet-handler/>
效果如下:
6.参数绑定注解@RequestParam
注解@RequestParam还有如下参数可以使用:
value: 与请求参数名称
required: 此在指定的请求参数是否必须包括,默认是true,提交时如果没有此参数则报错
defaultValue: 当没有指定请求参数时,则使用指定的默认值赋值
//参数绑定注解@RequestParam(将"name"映射到username)@RequestMapping(value = "/quick16")@ResponseBodypublic void save16(@RequestParam(value = "name", required = false, defaultValue = "印东升") String username) throws IOException {System.out.println(username);}
如果我们的请求参数是name,才会赋值给username,否则就采用默认的值。
7.获取Restful风格的参数
//获取Restful风格的参数(http://localhost:8080/spring_mvc_2/user2/quick17/yds)@RequestMapping(value = "/quick17/{username}")@ResponseBodypublic void save17(@PathVariable("username") String username) throws IOException {System.out.println(username);}
效果如下:
8.自定义类型转换器
首先我们需要创建一个日期转换器,让我们用一定的格式(yyyy-MM-dd)来将这样的格式字符串转化为Date类型数据:
public class DateConverter implements Converter<String,Date> {@Overridepublic Date convert(String dateStr) {//将日期字符串转换成日期对象,返回SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");Date date = null;try {date = simpleDateFormat.parse(dateStr);} catch (ParseException e) {throw new RuntimeException(e);}return date;}
}
然后我们需要声明这个转换器并加载驱动:
<!-- 声明转换器--><bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"><property name="converters"><list><bean class="com.yds.converter.DateConverter"></bean></list></property></bean>
<!-- 转换日期的驱动--><mvc:annotation-driven conversion-service="conversionService"/>
//自定义类型转换器(需要配置声明转换器)//http://localhost:8080/spring_mvc_2/user2/quick18?date=2025-9-4@RequestMapping(value = "/quick18")@ResponseBodypublic void save18(Date date) throws IOException {System.out.println(date);}
输入网址后效果如下:
9.获取Servlet相关的API
类似用Servlet回写数据,在形参声明这几个对象,框架就可以获取:
//获取Servlet相关的API@RequestMapping(value = "/quick19")@ResponseBodypublic void save19(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {System.out.println(request);System.out.println(response);System.out.println(session);}
效果如下:
10.获取请求头
使用注解@RequestHeader
@RequestHeader可以获得请求头信息,相当于web阶段学习的request.getHeader(name)
● value:请求头的名称
● required:是否必须携带此请求头
@RequestMapping(value = "/quick20")@ResponseBody //这里参数的名称需要和标准请求头参数的名称相同(这里尝试获取浏览器版本)public void save20(@RequestHeader(value = "User-Agent", required = false) String user_agent) throws IOException {System.out.println(user_agent);}
效果如下:
11.获得指定Cookie的值
使用@CookieValue可以获得指定Cookie的值
@CookieValue注解的属性如下:
● value:指定cookie的名称
● required:是否必须携带此cookie
@RequestMapping(value = "/quick21")@ResponseBodypublic void save21(@CookieValue(value = "JSESSIONID") String jsessionId) throws IOException {System.out.println(jsessionId);}
效果如下:
12.单文件上传和下载
首先要配置文件上传解析器:
<!-- 配置文件上传解析器--><bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><property name="defaultEncoding" value="UTF-8"/><property name="maxUploadSize" value="500000"/><property name="maxUploadSizePerFile" value="500000"/></bean>
@RequestMapping(value = "/quick22")@ResponseBodypublic void save22(String username, MultipartFile uploadFile,MultipartFile uploadFile2) throws IOException {System.out.println(username);
// System.out.println(uploadFile);//获得上传文件的名称String originalFilename = uploadFile.getOriginalFilename();uploadFile.transferTo(new File("C:\\upload\\"+ originalFilename));//多文件上传(第二个,其实跟第一个也一样)String originalFilename2 = uploadFile2.getOriginalFilename();uploadFile2.transferTo(new File("C:\\upload\\"+ originalFilename2));}
我们创建一个JSP文件用于测试:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %><html>
<head><title>Title</title>
</head>
<body><form action="${pageContext.request.contextPath}/user2/quick22" method="post" enctype="multipart/form-data">名称:<input type="text" name="username"><br/>文件:<input type="file" name="uploadFile"><br/>文件:<input type="file" name="uploadFile2"><br/><input type="submit" value="提交"><br/>
</form></body>
</html>
输入后效果如下:
13.多文件上传和下载
更改一下JSP文件:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %><html>
<head><title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user2/quick23" method="post" enctype="multipart/form-data">名称:<input type="text" name="username"><br/>文件:<input type="file" name="uploadFile"><br/>文件:<input type="file" name="uploadFile"><br/><input type="submit" value="提交"><br/>
</form>
<form action="${pageContext.request.contextPath}/user2/quick22" method="post" enctype="multipart/form-data">名称:<input type="text" name="username"><br/>文件:<input type="file" name="uploadFile"><br/>文件:<input type="file" name="uploadFile2"><br/><input type="submit" value="提交"><br/>
</form></body>
</html>
用遍历的方式来循环上传:
@RequestMapping(value = "/quick23")@ResponseBodypublic void save23(String username, MultipartFile[] uploadFile) throws IOException {System.out.println(username);for (MultipartFile multipartFile : uploadFile) {String originalFilename = multipartFile.getOriginalFilename();multipartFile.transferTo(new File("C:\\upload\\" + originalFilename));}}
输入后效果如下: