base黑马,视频链接:https://www.bilibili.com/video/BV1WZ4y1P7Bp?t=94.4
此系列文章可以当做视频的配套笔记,也可以当做自学SSM框架的教程。
SpringMVC的请求-获得请求参数-请求参数类型
SpringMVC的请求-获得请求参数-获得基本类型参数
@RequestMapping(value = "/quick11")
@ResponseBody //代表不进行页面跳转,以直接响应数据的方式进行回写数据,但是现在的返回值类型又是void,表示不进行数据回写,表示响应体是空的
public void save11(String username,int age){
//int age 写成 String age 是没有问题的,客户端请求任何参数都是字符串的形式
//int age也是可以的 SpringMVC的框架可以帮你进行数据类型的转换
//String username写成 int username是不可以的,因为不能把一个字符串汉字或者ABC转换成一个数字
System.out.println(username);
System.out.println(age);
}
启动项目进行测试:
SpringMVC的请求-获得请求参数-获得POJO类型参数
controller层:
@RequestMapping(value = "/quick12")
@ResponseBody
public void save12(User user){
System.out.println(user);
}
效果:
SpringMVC的请求-获得请求参数-获得数组类型参数
controller层中的代码:
@RequestMapping(value = "/quick13")
@ResponseBody
public void save13(String[] strs){
//数组打印的都是地址 list打印的都是值
System.out.println(Arrays.asList(strs));
}
效果:
SpringMVC的请求-获得请求参数-获得集合类型参数1
比如,现在准备一个表单,这个表单提交的是某些人的信息。
某些人是多个人,多个人得封装到集合当中。有一个集合,这个集合对应的泛型是User
controller代码1
@RequestMapping(value = "/quick14")
@ResponseBody
public void save14(List<User> userList){
//但是这样封装是封装不进去的
//得把List<User> userList 这个集合给包装到对象当中
//包装到POJO对象当中,这个POJO对象 一般叫做VO对象
}
创建VO类
package com.lyh.domain;
import java.util.List;
public class VO {
private List<User> userList;
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
@Override
public String toString() {
return "VO{" +
"userList=" + userList +
'}';
}
}
创建form.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/quick14" method="post">
<%-- 表明是第几个User对象的username、age--%>
<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="提交">
</form>
</body>
</html>
controller层代码:
@RequestMapping(value = "/quick14")
@ResponseBody
public void save14(VO vo){
System.out.println(vo);
}
效果:
SpringMVC的请求-获得请求参数-获得集合类型参数2
在webapp目录下面,建立ajax.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<%--引入jQuery--%>
<%--!!!!!!!!!!!!!注意引入JS文件不能使用单标签--%>
<script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js"></script>
<%--当页面一加载的时候,就让它发请求,这个请求发送的数据是JSON格式的数据--%>
<script>
var userList = new Array();
userList.push({username:"zhangsan",age:18});
userList.push({username:"lisi",age:38});
$.ajax({
type:"POST",
url:"${pageContext.request.contextPath}/user/quick15",
data:JSON.stringify(userList),
contentType:"application/json;charset=utf-8"
});
</script>
</head>
<body>
</body>
</html>
在webapp目录下建立js目录,把jquery-3.3.1.js文件复制到,建立的js目录下面。
controller层的代码
@RequestMapping(value = "/quick15")
@ResponseBody
public void save15(@RequestBody List<User> userList){
System.out.println(userList);
}
测试:在控制台上会报404
有这个jquery文件夹,但是,是找不到的
在spring-mvc.xml中加入一句话:
<!-- 这行代码写上之后 jquery就可以获取到了-->
<mvc:resources mapping="/js/**" location="/js/"/>
再次访问:
SpringMVC的请求-获得请求参数-静态资源访问的开启
controller层中的代码:
@RequestMapping(value = "/quick15")
@ResponseBody
//@RequestBody表示请求体,意味着要把请求体中的内容封装到List<User>这个集合中
public void save15(@RequestBody List<User> userList){
System.out.println(userList);
}
为什么找不到JQuery对应的文件?
原因在前端控制器的配置上。
SpringMVC的整个架构,它的前端控制器是DispatcherServlet。
/,叫做缺省的servlet
意味着客户端发送请求,这个请求到服务端找对应的servlet
找不到,最终这个资源都归,缺省的servlet进行处理
而我在web.xml中所用的都是SpringMVC开发的
内部没有其他的servlet,意味着我都不匹配
最终会找DispatcherServlet
DispatcherServlet 内部要帮你进行一个虚拟路径的匹配
匹配controller层中的@RequestMapping
(会把,jquery-3.3.1.js,这个东西也当成一个@RequestMapping和你进行匹配)
但是没有任何一个资源叫做 jquery-3.3.1.js
所以匹配不上,匹配不上就什么都不会干了。
所以最终的JQuery文件是不能被访问到的。
但是写上**<mvc:resources mapping=“/js/** ** **” location=“/js/”/> **这句话就可以
spring-mvc.xml中的配置
<!-- 在SpringMVC框架当中,要开放对那些资源的访问权限-->
<!-- 一般就是一些静态资源-->
<!-- 不需要去匹配对应的@RequestMapping了-->
<!-- 直接找到对应的静态资源返回就行-->
<!-- mapping代表映射地址,找谁-->
<!-- location表示是哪个目录下面的资源是对外开放的-->
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/img/**" location="/img/"/>
spring-mvc.xml中的配置写上这段话也是可以的
<!-- 代表在访问资源时,SpringMVC帮助找@RequestMapping对应的匹配地址-->
<!-- 找不到就交给原始的容器,而这里的原始的容器是TomCat-->
<!-- 就交给TomCat,让TomCat内部的机制去找静态资源-->
<!-- TomCat是有能力帮你找到静态资源的-->
<mvc:default-servlet-handler/>
<!-- SpringMVC框架如果帮你找不到对应的资源,就交给原始的容器TomCat-->
<!-- TomCat去帮你找对应的静态资源,帮你返回-->
在上面的基础上再去测试一下:
也是可以的。
SpringMVC的请求-获得请求参数-配置全局乱码过滤器
服务器使用的是TomCat 8.5的版本
get请求中文本身是不乱码的
post会出现乱码的问题
对于他要进行相应的解决。
使用之前的form表单进行测试,表单的请求方式是post
现在去访问一下form表单
后台会出现乱码的情况
配置过滤器
把这个filter配置上之后,与此同时指定一个参数encoding
filter内部有一个初始化参数是encoding,这个encoding对应的值就设置编码UTF-8就行。
对所有的资源都要进行一个编码过滤。
在web.xml文件中配置全局过滤字符编码格式的filter
<!--配置全局过滤的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>
提交测试:
效果:
SpringMVC的请求-获得请求参数-参数绑定注解@RequestParam
controller层的代码:
@RequestMapping(value = "/quick16")
@ResponseBody
public void save16(String username){
System.out.println(username);
}
地址栏的输入:
效果:
但是现在有个问题:如果这里输入的是name
控制台会输出空
controller层的代码:
@RequestMapping(value = "/quick16")
@ResponseBody //这里写客户端在请求时,请求的那个名称
//将请求的 name参数 给映射到 username上
//如果当前的参数只有1个,并且当前的参数是value的话,是可以省略掉的
public void save16(@RequestParam(value = "name") String username){
System.out.println(username);
}
地址栏:
效果:
如果地址栏,这样写的话,会报错的。
会出错,因为在默认的情况下,必须得携带name参数
@RequestMapping(value = "/quick16")
@ResponseBody //这里写客户端在请求时,请求的那个名称
//将请求的 name参数 给映射到 username上
//如果当前的参数只有1个,并且当前的参数是value的话,是可以省略掉的
//required = false 意味着在请求时,name属性,不是必须要携带的了
public void save16(@RequestParam(value = "name",required = false) String username){
System.out.println(username);
}
效果:
此时,不会出错。控制台是 null
controller层代码:
@RequestMapping(value = "/quick16")
@ResponseBody
//defaultValue 是默认值,当没有指定的请求参数时,则使用默认的值
public void save16(@RequestParam(value = "name",required = false,defaultValue = "Hello,NiHao!!") String username){
System.out.println(username);
}
效果:
SpringMVC的请求-获得请求参数-Restful风格的参数的获取
并不是以**?**的方式携带数据的。而是把想请求的数据放到url地址内部的。
controller层代码:
//这里可以用method属性,来设置是用get请求还是用post等的请求方式
@RequestMapping(value = "/quick17/{username}")
@ResponseBody
public void save17(@PathVariable(value ="username")String username){
System.out.println(username);
}
效果:
SpringMVC的请求-获得请求参数-自定义类型转换器
SpringMVC 本身框架内部具备一些已经定义好的类型转换器。
客户端请求的任何数据到达服务端之后,都是字符串。
但是在封装数据的时候,会发现,方法内部的形参如果是数字的话,也可以正常的封装。
说明SpringMVC这个框架,自动的已经把字符串给转换成了数字,封装到参数上了。
SpringMVC已经具备一些转换器了,但是这些转换器不能满足我们的需求。
1、Converter是SpringMVC提供的一个接口,复写它的方法
2、在spring-mvc.xml这个文件中声明转换器
把定义好的转换器配置到转换服务工厂内部就可以了
3、把这个转换服务工厂,交给在其内部引用转换服务工厂。
controller层:
@RequestMapping(value = "/quick18")
@ResponseBody
public void save18(Date date){
System.out.println(date);
}
效果:
但是我们一般不用 2023/01/02 这种格式,可能用2023-01-02这种格式
上面的格式会出错。因为格式不匹配。
创建包:com.lyh.converter,在该包中创建 DateConverter类,实现SpringMVC转换器接口Converter<S,T>
package com.lyh.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> {
@Override //这个String就是日期字符串
public Date convert(String dataStr) {
//将日期的字符串 转换成 正真的日期对象 返回即可
//在内部可以指定格式,也可以把格式提成配置文件,可以自定义修改
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
//解析 dataStr
Date date = null;
try {
date = format.parse(dataStr);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
转换完了之后,还是不可以用的,得告诉SpringMVC
在 spring-mvc.xml 中
<!-- 声明转换器-->
<!-- 其实在这个地方定义的是一个转换器服务的工厂对象-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<!-- 要自己自定义转换器的全限定名称-->
<!-- 让工厂去帮我们造这个日期转换器的bean-->
<bean class="com.lyh.converter.DateConverter"></bean>
</list>
</property>
</bean>
<!-- mvc的注解驱动-->
<!-- conversion-service 就是 上面起的名字 id="conversionService"-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!-- 注册完之后,下次再进行相应的注解扫描的时候 就会使用 指定的转换器 去 完成对应的日期转换-->
测试:
SpringMVC的请求-获得请求参数-获得Servlet相关API
quickMethod16(),这个方法是框架帮忙调用的,方法内的参数都是形参,SpringMVC框架调用方法负责向里面传递实际参数。
controller层:
@RequestMapping(value = "/quick19")
@ResponseBody
//想要一个User,让SpringMVC注入一个User,这样是不行的。SpringMVC注入一些公用的对象
//这些是TomCat产生,交给SpringMVC的
public void save19(HttpServletRequest request, HttpServletResponse response, HttpSession session){
System.out.println(request);
System.out.println(response);
System.out.println(session);
}
效果:
看到了catalina,就等价与TomCat。
这三个对象都是TomCat帮你产生的。
只不过传给SpringMVC框架。SpringMVC框架在调用方法的时候,又传递到方法的形参中。
SpringMVC的请求-获得请求参数-获得请求头信息
HTTP请求刨除请求数据之外,还有请求头和请求行。
顺序应该是请求行、请求头、请求数据。
请求头是键值对的形式,是头的名称和头的值。
一般情况是根据头的名称去获取对应的值。
controller层:
@RequestMapping(value = "/quick20")
@ResponseBody
public void save20(){
}
访问quick20,进行抓包
这里面有请求头和响应头。
User-Agent代表当前浏览器的一些信息。
controller层:
@RequestMapping(value = "/quick20")
@ResponseBody //这里的名字得和浏览器抓包请求的agent是一致的 不是必须的
public void save20(@RequestHeader(value = "User-Agent",required = false) String user_agent){
System.out.println(user_agent);
}
效果:
在请求头中有一个比较特殊的就是Cookie
controller层
@RequestMapping(value = "/quick21")
@ResponseBody
public void save21(@CookieValue(value = "JSESSIONID",required = false) String jsessionId){
System.out.println(jsessionId);
}
效果:
@RequestHeader 是根据前面的名字获得后面的值
@CookieValue,是根据JSESSIONID这个名字获得JSESSIONID的值,要更深入一层。
SpringMVC的请求-文件上传-客户端表单实现
文件上传也属于客户端把数据发送到服务器端,服务器端接收客户端请求的数据。
这个时候接收的数据就不是一个普通的数据了,就是一个文件。
文件上传客户端三要素
- 得有一个文件上传项,有一个按钮,一点击就去选择文件。
- 这个文件上传项所在的表单得是post的提交方式。
- 文件上传项,所在的表单enctype属性,必须是一个多部分表单,不能是原始默认的URL编码方式的。
在webapp文件下创建upload.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body> <%--文件上传 必须选择 多部分表单形式--%>
<form action="${pageContext.request.contextPath}/user/quick22" method="post" enctype="multipart/form-data">
名称<input type="text" name="username"><br>
文件<input type="file" name="upload"><br>
<input type="submit" value="提交"><br>
</form>
</body>
</html>
如果是url编码方式,提交参数的格式都是键值对的形式
key=value & key=value
测试:
SpringMVC的请求-文件上传-文件上传的原理
像**request.getParameterMap()**等方法都将会失效。
因为 request 在 get 某个方法时,获得的是URL编码方式的那个表单提交。
现在的表单是多部分表单形式,所以这些API都失效了。
多部分表单,包括我整个表单的全部数据。
服务端可以获取这些数据, 因为这些数据都在HTTP请求体当中。
服务端可以获得当前表单的所有数据。
服务端怎么去获取对应的数据?
在web阶段时:
HTTP请求体都在这里,用最原始的java基础可以获取值,获取完之后通过字符串的切割等等相应的操作可以获取对应的数据。
但是太麻烦了
在web阶段学习文件上传时,借助的是Apache的 fileupload这个插件, 这个插件将文件上传对应的API封装的比较完全,操作比较简单。
SpringMVC框架阶段:
但是现在更简单,因为今天用的是SpringMVC框架
SpringMVC底层封装的也是fileupload这个插件。
文件上传的第一步是导入插件对应的坐标。
SpringMVC的请求-文件上传-单文件上传的代码实现1
web阶段也得导入fileupload 和 io 的坐标。
在pom.xml文件中导入相关的坐标:
<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.3</version>
</dependency>
这个文件上传解析器是Spring提供的一个叫做 CommonsMultipartResolver 这样的一个对象。
在 spring-mvc.xml 中进行相应的配置
<!-- 配置文件上传的解析器-->
<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>
controller层相关代码:
@RequestMapping(value = "/quick22")
@ResponseBody
public void save22(String username, MultipartFile uploadFile){
System.out.println(username);
//这里也是先打印一下 先看一下到底是不是空的 如果是空的就没有办法操作其他的了
//如果不是空的 是对象 才可以对内部取相应的数据
System.out.println(uploadFile);
}
效果:
点击 **提交 **之后的效果:
说明文件已经上传成功了。
SpringMVC的请求-文件上传-单文件上传的代码实现2
将文件进行保存
就是以指定的名称将文件存到我的服务器的磁盘上
建立一个测试文件夹:D盘下面的MyTest文件夹。
controller层:
@RequestMapping(value = "/quick22")
@ResponseBody
public void save22(String username, MultipartFile uploadFile) throws IOException {
System.out.println(username);
//获得上传文件的名称,肯定找对应的文件对象 uploadFile
//uploadFile.getName();//这个代表上传文件表单项的名称,就是和uploadFile的对应值
String originalFilename = uploadFile.getOriginalFilename(); //这个是文件的名称
//获得完文件的名称了 得把这个文件存到某个位置
//可以用原始的IO去存
//但是 uploadFile 这个对象 本身就有相应的方法
//就将这个文件 转移到哪儿 内部要一个file对象
uploadFile.transferTo(new File("D:\\MyTest\\"+originalFilename));//加上文件名称
//这就代表把文件,上传的文件,转移到服务器的某个磁盘上了
}
效果:
点击 **提交 **按钮
控制台上
D盘下面的MyTest文件夹
打开文件后的内容:
原始文件中的内容:
SpringMVC的请求-文件上传-多文件上传的代码实现
多文件上传和单文件上传的格式方法是一样的。
upload.jsp 代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body> <%--文件上传 必须选择 多部分表单形式--%>
<form action="${pageContext.request.contextPath}/user/quick22" method="post" enctype="multipart/form-data">
名称<input type="text" name="username"><br>
<%--这里的名字得和conroller层 方法内部相应参数的名字一致--%>
上传文件1:<input type="file" name="uploadFile"><br>
上传文件2:<input type="file" name="uploadFile2"><br>
<input type="submit" value="提交"><br>
</form>
</body>
</html>
controller层代码:
@RequestMapping(value = "/quick22")
@ResponseBody
public void save22(String username, MultipartFile uploadFile,MultipartFile uploadFile2) throws IOException {
System.out.println(username);
String originalFilename = uploadFile.getOriginalFilename();
uploadFile.transferTo(new File("D:\\MyTest\\"+originalFilename));
String originalFilename2 = uploadFile2.getOriginalFilename();
uploadFile2.transferTo(new File("D:\\MyTest\\"+originalFilename2));
}
效果:
点击提交按钮:
服务端代码:
upload.jsp中建一个新的表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/quick22" method="post" enctype="multipart/form-data">
名称<input type="text" name="username"><br>
上传文件1:<input type="file" name="uploadFile"><br>
上传文件2:<input type="file" name="uploadFile"><br>
<input type="submit" value="提交"><br>
</form>
<form action="${pageContext.request.contextPath}/user/quick22" method="post" enctype="multipart/form-data">
名称<input type="text" name="username"><br>
<%--这里的名字得和conroller层 方法内部相应参数的名字一致--%>
上传文件1:<input type="file" name="uploadFile"><br>
上传文件2:<input type="file" name="uploadFile2"><br>
<input type="submit" value="提交"><br>
</form>
</body>
</html>
controller层:
@RequestMapping(value = "/quick23")
@ResponseBody //有多个就是数组
public void save23(String username, MultipartFile[] uploadFile) throws IOException {
System.out.println(username);
for (MultipartFile multipartFile : uploadFile) {
String originalFilename = multipartFile.getOriginalFilename();
multipartFile.transferTo(new File("D:\\MyTest\\"+originalFilename));
}
}
效果:
点击 **提交 **按钮
SpringMVC的请求-知识要点
SpringMVC作为web层的框架,最主要的工作是获得客户端的请求,最终给客户端进行响应。