springMVC是web层框架。
之前javaweb时,servlet中总重复很多封装参数实体之类的公有行为,可使用baseServlet或filter抽取一个前端控制器。现在springMVC也可作为前端控制器。
springMVC可通过一套注解让Java类直接变为处理请求的控制器,无需实现任何接口如servlet的HttpServlet接口。
SpringMVC快速入门
mavenWeb项目,pom文件引入spring-webmvc、servlet、jsp的依赖:
<?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>org.example</groupId>
<artifactId>SpringModule</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/SpringMvcModule</path><!--虚拟目录-->
</configuration>
</plugin>
</plugins>
</build>
</project>
web.xml文件配置springMVC前端控制器
<?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">
<!--配置SpringMVC的前端控制器:
配置一个servlet,类选择第三方org.springframework的DispatcherServlet
配置该类,且路径为拦截所有来作为springMvc的前端控制器servlet -->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param><!--该servlet的初始化参数-->
<!--spring-mvc.xml是怎么加载的呢
spring-mvc.xml是怎么加载的呢
类似web.xml中的<context-param>application域的全局初始化参数。
这里下面配置初始化参数spring-mvc.xml名称即为web.xml中该DispatcherServlet的servlet的init初始化参数来提供,
以便org的DispatcherServlet根据这个servlet的init初始化参数去加载springMVC的配置文件,
继而IOC出controller(特有行为)实例提供给前端控制器DispatcherServlet(共有行为)使用。
-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup><!--loadOnStartup=负整数或不加默认第一次访问该servlet执行时创建servlet对象并初始化
loadOnStartup为0或正整数时,web服务器启动时创建servlet对象,数字越小,优先级越高-->
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern><!-- 配置该servlet的路径为拦截所有/,虽会覆盖tomcat静态资源访问路径,但现在没有静态资源html之类,只有jsp动态页面。-->
</servlet-mapping>
</web-app>
com.kdy.controller包中创建UserController
@Controller
public class UserController {
@RequestMapping("/quickStart")//资源路径
public String save(){
System.out.println("Controller save running...");
return "success.jsp";//springMVC的跳转方式
/* return "forward:/hello.jsp";//不写forward也默认forward
return "redirect:/hello.jsp";//重定向,且springMvc会自动加上重定向的虚拟路径 */
}
}
resource目录下仅创建spring-mvc.xml配置文件
里面加上spring中学的组件扫描注解,以便@controller 被扫描到从而生成实例。
这里仅创建spring-mvc.xml配置文件即可,无需创建applicationContext.xml。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--Controller的组件扫描-->
<context:component-scan base-package="com.kdy">
<!--里面可加子标签:
<context:include-filter type="annotation" expression="具体包名或具体到类"代表扫描包含的内容,
<context:exclude-filter type="annotation" expression="具体包名或具体到类"代表不包含的包内容。-->
</context:component-scan>
</beans>
webapp中jsp目录创建success.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h1>success!</h1>
</body>
</html>
配置tomcat部署运行访问如下路径资源即可
spring-mvc.xml是怎么加载的呢
类似web.xml中的<context-param>application域的全局初始化参数。这里的spring-mvc.xml名称也作为web.xml中servlet的init初始化参数来提供,以便org的DispatcherServlet根据这个servlet的init初始化参数去加载springMVC的配置文件,继而IOC出controller(特有行为)实例提供给前端控制器DispatcherServlet(共有行为)使用。
springMVC作为前端控制器获取请求资源地址,继而映射访问真实资源controller。
SpringMvc执行流程
浏览器访问tomcat,路径发给前端控制器,先通过HandlerMapping(类似Filter)返回个处理器执行链(器对象)给前端控制器,前端控制器再把该执行链发给HandlerAdaptor处理,继而发给Handler(即controller)处理,再而Adaptor返回ModelAndView(如jsp)给前端控制器,前端控制器再通过视图解析器将jsp解析为html之类,再返回给前端控制器转发浏览器渲染。
SpringMVC注解
@RequetMapping 加在类上表示请求URL的第一级访问目录,controller较多时好作为区分模块;加在方法上表示URL的第二级访问目录。
一级访问目录加上二级访问目录组成资源的访问虚拟路径。
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/quick")
public String save() {
System.out.println("Controller save running...");
/*
1.如果类上不加@RequestMapping("/user"),且hello.jsp在webapp根目录下,直接return "hello.jsp";
则访问http://localhost:8080/SpringMvcModule/quick会return到webapp根目录下的hello.jsp访问成功。
2.但如果在类上加上@RequestMapping("/user"),且hello.jsp在webapp根目录下,且直接return "hello.jsp";
则访问http://localhost:8080/SpringMvcModule/user/quick时,就访问不到hello.jsp。
原因是:这里return "hello.jsp";因为类上加了@RequestMapping("/user"),就默认访问的是webapp目录下的user目录下的hello.jsp,没有这个user目录所以找不到。
解决方式:return "/hello.jsp";即可。在return的hello.jsp字符串前面加一个/斜线即可。仍然return到webapp根目录下的hello.jsp
*/
return "/hello.jsp";
/* return "forward:/hello.jsp";//不写forward也默认forward
return "redirect:/hello.jsp";//重定向 且springMvc会自动加上重定向的虚拟路径 */
}
/*
* @RequestMapping的参数属性
* method = RequestMethod.GET表示请求方法必须为GET才允许访问该资源
* params参数限定,必须有无某些参数或值为多少才允许访问资源,支持简单的表达式。
* params={"name"}表示请求参数必须有name才允许访问该资源
* params={"age!30"}表示请求参数age不为30才允许访问该资源
* headers = {"Cookie"}表示请求头必须携带Cookie才允许访问...
* */
@RequestMapping(value = "/quick",method = RequestMethod.GET,params={"name","age!30"},headers = {"Cookie"})
public String save2() {
System.out.println("Controller save running...");
return "/hello.jsp";
/* return "forward:/hello.jsp";//不写forward也默认forward
return "redirect:/hello.jsp";//重定向 且springMvc会自动加上重定向的虚拟路径 */
}
}
SpringMvc配置视图解析器(xml方式)
SpringMvc组件解析
我们引入spring-webmvc的依赖后,可在External Libraries中看找到org的spring-webmvc目录,点开jar包,找到web.servlet找到DispatcherServlet.properties中有相应的组件配置。
从而我们可用选中具体的类双击shift查看源码。
SpringMvc配置视图解析器(xml方式)
spring-webmvc的DispatcherServlet.properties配置的InternalResourceViewResolver继承的父类UrlBasedViewResolver中定义了FORWARD_URL_PREFIX=“forward”和REDIRECT_URL_PREFIX= "redirect:",所以我们上面controller直接return省略了转发的前缀,我们也可以手动加上如return "forward:/success.jsp",如果要重定向需要手动加上如:return "redirect:/success.jsp"
配置return的内容的前缀和后缀
resource下的spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--Controller的组件扫描-->
<context:component-scan base-package="com.kdy"></context:component-scan>
<!--配置内部资源视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp"></property><!--前缀-->
<property name="suffix" value=".jsp"></property><!--后缀-->
</bean>
</beans>
webapp目录下有jsp目录下的success.jsp文件
com.kdy.controller中UserController中的return语句即可写为
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/quick")
public String save() {
System.out.println("Controller save running...");
return "/success";
//return "redirect:/jsp/success.jsp";//重定向的话路径写全名
//如果return的内容有redirect:或forward:修饰,则配置的视图解析器前缀后缀不生效
//注:重定向时的虚拟路径不用加也行,springMvc会自动加上重定向的虚拟路径
}
}
SpringMvc数据响应方式
1.页面跳转:直接return 字符串跳转页面、通过return ModuleAndView对象跳转页面
2.回写数据:返回字符串数据、返回对象或集合
页面跳转--返回字符串跳转页面
直接return 字符串跳转页面见上。
页面跳转--返回ModuleAndView对象跳转页面
com.kdy.controller中的UserController
@Controller
@RequestMapping("/user")
public class UserController {
/*方法体内new一个modelAndView,返回modelAndView*/
@RequestMapping("/quick")
public ModelAndView save() {
System.out.println("Controller save running...");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", "zhangsan");//放到request域中
modelAndView.setViewName("/success");//这里字符串会经过xml中配置的视图解析器处理,拼上前缀后缀,请求转发
/* modelAndView.setViewName("forward:/jsp/success.jsp");
modelAndView.setViewName("redirect:/jsp/success.jsp");
如果内容有redirect:或forward:修饰,则配置的视图解析器前缀后缀不生效*/
//注:重定向的虚拟路径:springMvc会自动加上重定向的虚拟路径
return modelAndView;
}
/*入参的参数中注入ModuleAndView对象,返回modelAndView*/
@RequestMapping("/quick2")
public ModelAndView save2(ModelAndView modelAndView) {
System.out.println("Controller save2 running...");
modelAndView.addObject("name", "zhangsan");//放到request域中
modelAndView.setViewName("/success");//这里字符串会经过xml中配置的视图解析器处理,拼上前缀后缀,请求转发
return modelAndView;
}
/*返回String字符串跳转具体页面,入参参数中注入model对象,设置其request域携带的数据*/
@RequestMapping("/quick3")
public String save3(Model model) {
System.out.println("Controller save3 running...");
model.addAttribute("name", "zhangsan");//放到request域中
return "/success";//这里字符串会经过xml中配置的视图解析器处理,拼上前缀后缀,请求转发
}
/*返回String字符串跳转具体页面,原生HttpServletRequest传参:
* 不常用,我们常用上面几种框架提供的对象,方便与javaWeb解耦
* */
@RequestMapping("/quick4")
public String save4(HttpServletRequest request) {
System.out.println("Controller save4 running...");
request.setAttribute("name", "zhangsan");//放到request域中
return "/success";//这里字符串会经过xml中配置的视图解析器处理,拼上前缀后缀,请求转发
}
}
webapp下jsp中有个success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h1>success</h1>
name:${name}
</body>
</html>
回写数据--返回字符串数据
com.kdy.controller包中UserController
@Controller
@RequestMapping("/user")
public class UserController {
/*借助入参注入的HttpServletResponse对象,回写字符串到网页。回参为void*/
@RequestMapping("/quick")
public void save(HttpServletResponse response) throws IOException {
System.out.println("Controller save running...");
// response.getWriter().write("hello String response print");
response.getWriter().println("hello String response print");
}
/*借助SpringMvc注解@ResponseBody,return 字符串会作为数据字符串回写网页
如果有中文乱码,需要设置produces 如@RequestMapping(value = "/save",produces = "text/html;charset=UTF-8")*/
@RequestMapping("/quick2")
@ResponseBody
public String save2(){
return "hello @ResponseBody String";
}
}
回写数据--返回字符串数据:对象转json字符串
pom文件除了引入spring-webmvc、servlet、jsp三个依赖外,再引入以下1+3个依赖
fastjson依赖可单独使用,对应下面controller代码中的/quick3的save3方法。
jackson-core和jackson-databind和jackson-annotation三个依赖需一起使用,对应下面controller代码中/quick2的save2方法。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.74</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.10.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.3</version>
</dependency>
com.kdy.domain中创建User类(get、set、toString)
public class User {
private String name;
private int age;
//get、set、toString
}
com.kdy.controller中的UserController
@Controller
@RequestMapping("/user")
public class UserController {
/*@ResponseBody返回字符串,手写json*/
@RequestMapping("/quick")
@ResponseBody
public String save() {
return "{\"name\":\"zhangsan\",\"age\":18}";
}
/*@ResponseBody返回字符串,借助(jackson-core和jackson-databind和jackson-annotation三个依赖)的json转换工具,
将对象转json
如果有中文乱码,需要设置produces 如@RequestMapping(value = "/save",produces = "text/html;charset=UTF-8")**/
@RequestMapping("/quick2")
@ResponseBody
public String save2() throws JsonProcessingException {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(user);
return json;
}
/*@ResponseBody返回字符串,借助(fast-json依赖的)json转换工具,将对象转json*/
@RequestMapping("/quick3")
@ResponseBody
public String save3() throws JsonProcessingException {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
String json = JSON.toJSONString(user);
//User user = JSON.parseObject(jsonStr,User.class);
return json;
}
}
回写数据--返回对象或集合
我们引入spring-webmvc的依赖后,可在External Libraries中看找到org的spring-webmvc目录,点开jar包,找到web.servlet找到DispatcherServlet.properties中有相应的组件配置。
从而我们可用选中具体的类双击shift查看源码。
配置适配器HandlerAdapter(定义json转换器)
spring-webmvc的依赖的DispatcherServlet.properties中的HandlerAdapter配置中有一个类是RequestMappingHandlerAdapter,双击shift跟进后有一个参数messageConverters并提供了set方法。所以我们就可以通过spring-mvc.xml配置文件给这RequestMappingHandlerAdapter适配器去注入一个json的转换器的属性。
spring-mvc.xml中配置处理器映射器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--Controller的组件扫描-->
<context:component-scan base-package="com.kdy"></context:component-scan>
<!--配置内部资源视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp"></property><!--前缀-->
<property name="suffix" value=".jsp"></property><!--后缀-->
</bean>
<!--配置处理器映射器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</list>
</property>
</bean>
</beans>
com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {
/*@ResponseBody返回对象,实际经过是配置的转换器将该对象转成json后在发给下一步(视图解析器等响应给网页)*/
@RequestMapping("/quick")
@ResponseBody
public User save() {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
}
SpringMvc注解驱动
springMVC多个组件中,处理器映射器、处理器适配器、视图解析器称为三大组件。
上面使用@ResponseBody加spring-mvc.xml中配置处理器映射器的json的转换器返回对象的配置xml方式比较繁琐。
我们可用使用一个springmvc的注解驱动<mvc:annotation-driven/>来自动加载处理器映射器和处理器适配器。且底层默认继承jackson进行对象或集合的json格式字符串转换。
换句话说,使用<mvc:annotation-driven/>可替代上面spring-mvc.xml配置的处理器映射器。
resource下的spring-mvc.xml文件就改为了
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--Controller的组件扫描-->
<context:component-scan base-package="com.kdy"></context:component-scan>
<!--配置内部资源视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp"></property><!--前缀-->
<property name="suffix" value=".jsp"></property><!--后缀-->
</bean>
<mvc:annotation-driven/>
</beans>
con.kdy.controller的UserController
@Controller
@RequestMapping("/user")
public class UserController {
/*@ResponseBody返回对象,实际经过是配置的转换器将该对象转成json后在发给下一步(视图解析器等响应给网页)*/
@RequestMapping("/quick")
@ResponseBody
public User save() {
User user = new User();
user.setName("zhangsan");
user.setAge(18);
return user;
}
}
SpringMvc获得请求参数
基本数据类型、POJO类型数据、数组类型参数、集合类型参数
基本类型、POJO、数组、集合类型
com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {
/*springMvc获取基本数据类型请求参数
*
* 需要请求参数名和controller中资源方法的入参参数名完全一致。
* 请求参数名和入参对应后,springmvc会自动类型转换,将前端String类型转成其他类型。
* 访问:http://localhost:8080/SpringMvcModule/user/quick?name=zhangsan&age=18
* */
@RequestMapping("/quick")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save(String name,int age) {
System.out.println(name);
System.out.println(age);
}
/*springMvc获取POJO数据类型请求参数
*
* 需要请求参数名称和controller中资源方法的入参POJO对象的属性名(能在POJO属性中找到)完全一致,
* springMvc会自动封装,即springMvc实例入参对象时会将属性注入
* 访问:http://localhost:8080/SpringMvcModule/user/quick2?name=zhangsan&age=18
* */
@RequestMapping("/quick2")
@ResponseBody
public void save2(User user) {
System.out.println(user);
}
/*springMvc获取数组类型请求参数
*
* 需要请求参数名称和controller中资源方法的入参数组名完全一致,
* 参数值会自动映射匹配
* 访问:http://localhost:8080/SpringMvcModule/user/quick3?strs=aaa&strs=bbb&strs=ccc
* */
@RequestMapping("/quick3")
@ResponseBody
public void save3(String[] strs) {
System.out.println(Arrays.asList(strs));
}
/*springMvc获取集合类型请求参数:方式一:创建VO类封装集合
*
* springMvc暂未提供集合类型自动封装工具,故不可写(List<User> userList)这种入参。
* 我们可用借助springMvc封装Pojo类型的方式,创建一个类,将List<User> userList作为成员属性,并提供set方法
* 这样对于前端的集合类型参数,即可自动注入到该类实例中。我们称这个类为VO。
* 访问:http://localhost:8080/SpringMvcModule/jsp/form.jsp
* 具体jsp文件见webapp下jsp的form.jsp 通过表单发送post请求到本资源
* */
@RequestMapping("/quick4")
@ResponseBody
public void save4(VO vo) {
System.out.println(vo);
}
/*springMvc获取集合类型请求参数:方式二:对于Ajax请求传递过来的json格式的List集合
* 直接使用@RequestBody 加json前的类型,spring自动将json转成对象
*
* 通过webapp目录下js目录下引入jQuery-3.7.0.js官网下载
* 通过webapp下jsp下创建ajax.jsp,通过script发jquery的ajax请求,创建List<User>集合数据并转json发送到本资源
* 注:js属于静态资源,载web.xml中配置了前端控制器配成了/拦截了所有资源去发配给controller,所以
* 我们要载spring-mvc.xml中配置静态资源放行<mvc:resources location="/" mapping="/星星/星.js"/>
* */
@RequestMapping("/quick5")
@ResponseBody
public void save5(@RequestBody List<User> userList) {
System.out.println(userList);
}
}
com.kdy.domain中的User:生成get、set、toString
public class User {
private String name;
private int age;
}
/quick4用到的VO,com.kdy.domain中的VO:get、set、toString
public class VO {
private List<User> userList;
}
/quick4用到的webapp下jsp下的form.jsp里bady里的内容
<form action="${pageContext.request.contextPath}/user/quick4" method="post">
user1:<br/>
name:<input type="text" name="userList[0].name"><br/>
<%--这里form表单input的name如果走springMvc封装POJO参数需要和POJO属性名完全一致
访问资源路径方法的入参是VO类,其属性为List<User> userList,
由于是集合类型我们可用用userList[0]这种下标方式传值入参,
再如如果VO中的属性是User user,我们可用user.name和user.age继续赋值,
类推这里我们可用userList[0].name和userList[0].age进行对各下标的数组元素进行赋值
--%>
age:<input type="text" name="userList[0].age"><br/>
user2:<br/>
name:<input type="text" name="userList[1].name"><br/>
age:<input type="text" name="userList[1].age"><br/>
user3:<br/>
name:<input type="text" name="userList[2].name"><br/>
age:<input type="text" name="userList[2].age"><br/>
<input type="submit" value="submit">
</form>
/quick5用到的webapp下的js目录下的jQuery-3.7.0.js从官网下载
/quick5用的的webapp下的jsp下的ajax.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>ajax</title>
</head>
<body>
</body>
<script src="${pageContext.request.contextPath}/js/jquery-3.7.0.js"></script>
<script>
var userList = new Array();
userList.push({username:"zhangsan",age:18});
userList.push({username:"zhangsan2",age:20});
$.ajax({
type:"POST",
url:"${pageContext.request.contextPath}/user/quick5",
data:JSON.stringify(userList),
contentType:"application/json;charset=utf-8"
});
</script>
</html>
/quick5用到的,spring-mvc.xml中静态资源放行
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--Controller的组件扫描-->
<context:component-scan base-package="com.kdy"></context:component-scan>
<!--配置内部资源视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp"></property><!--前缀-->
<property name="suffix" value=".jsp"></property><!--后缀-->
</bean>
<!--注解驱动,顶替配置的处理器映射器和适配器,集成了jackson,可Controller资源方法返回字为对象User时,自动转为json-->
<mvc:annotation-driven/>
<!--js和css和html等被web.xml中配置的前端控制配置拦截了,
这里配置springMvc静态资源放行-->
<!--springMvc开放静态资源的访问路径。mapping表示的是映射地址,location表示的是哪个目录下的资源是对外开放的-->
<mvc:resources mapping="/js/**" location="/js/"/><!--就表示访问路径为/js/**时,在/js/目录下的资源是对外开放的-->
<!-- <mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/html/**" location="/html/"/>-->
<!--上面的<mvc:resources location="/" mapping="/**/*.js"/>等等也可配置为以下代码-->
<!-- <mvc:default-servlet-handler/> 若使用这种方式,必须配置注解驱动,否则controller无法访问-->
<!-- 意思就是在访问资源时,springMvc帮我们找对于controller的地址,
如果找不到,就交给原始容器tomcat容器帮我们找静态资源的地址。-->
</beans>
spring-mvc.xml中静态资源放行
<!--js和css和html等被web.xml中配置的前端控制配置拦截了,
这里配置springMvc静态资源放行-->
<!--springMvc开放静态资源的访问路径。mapping表示的是映射地址,location表示的是哪个目录下的资源是对外开放的-->
<mvc:resources mapping="/js/**" location="/js/"/><!--就表示访问路径为/js/**时,在/js/目录下的资源是对外开放的-->
<!-- <mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/html/**" location="/html/"/>-->
<!--上面的<mvc:resources location="/" mapping="/**/*.js"/>等等也可配置为以下代码-->
<!-- <mvc:default-servlet-handler/>若使用这种方式,必须配置注解驱动,否则controller无法访问-->
<!-- 意思就是在访问资源时,springMvc帮我们找对于controller的地址,
如果找不到,就交给原始容器tomcat容器帮我们找静态资源的地址。-->
请求参数乱码问题
tomcat8的post请求存在中文乱码问题,javaWeb阶段req.setCharacterEncoding("UTF-8")来解决,现阶段可在web.xml中设置SpringMvc的字符编码过滤器的filter来解决。
注:web.xml标签需要遵循一定顺序来写,否则不生效。
webapp的WEB-INF的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">
<!--springMvc字符编码过滤器-->
<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的前端控制器:-->
<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>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
还是上面请求参数的案例,重启tomcat,进入8080/SpringMvcModule/jsp/form.jsp
输入一些中文字符点击提交表单,就会post请求提交到/quick4路径的controller里了。
SpringMvc参数绑定注解@RequestParam
如请求参数和controller方法中的入参参数名不完全一样,可用借助@RequestParam映射
@Controller
@RequestMapping("/user")
public class UserController {
/*若controller入参参数名和请求参数名不完全一致可用@RequestParam绑定请求参数到入参参数上
* 访问http://localhost:8080/SpringMvcModule/user/quick?username=zhangsan 不加参数会报错(required默认true)
* */
@RequestMapping("/quick")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save(@RequestParam("username") String name) {
System.out.println(name);
}
/*@RequestParam的参数
* required:指定的请求参数是否必须包含,默认true,提交时如果没有该参数会报错
* defaultValue:如果没有指定请求参数,则使用默认值赋值
* 访问http://localhost:8080/SpringMvcModule/user/quick
* */
@RequestMapping("/quick2")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save2(@RequestParam(value = "username",required = false,defaultValue = "zhangsanDefault") String name) {
System.out.println(name);
}
}
获得Restful风格参数
RestFul使用url+请求参数,如/user/1 GET等等。
Http常用动词GET获取、POST新增、PUT更新、DELETE删除
controller中可用路径中的{name}占位符配合入参中使用@PathVariable(name)String name
@Controller
@RequestMapping("/user")
public class UserController {
/*
* 获取Restful风格参数
* 访问:http://localhost:8080/SpringMvcModule/user/quick/张三
* @PathVariable参数:required默认true,也只能为true,改成false不生效,还是要传递后面占位符参数如/quick/zhangsan
* */
@RequestMapping("/quick/{name}")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save(@PathVariable("name") String name) {
System.out.println(name);
}
}
SpringMvc获取日期参数
@Controller
@RequestMapping("/user")
public class UserController {
/*
* 获取日期类型参数
* 访问 http://localhost:8080/SpringMvcModule/user/quick?date=2021/02/22
* */
@RequestMapping("/quick")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save(Date date) {
System.out.println(date);
}
}
日期(yyyy-MM-dd格式)--自定义类型转换器
springMvc提供了一些简单的类中转换器,如请求参数String的age,自动转为int的age入参。
对于Date类型,如果请求参数为date=2021/02/22,这时controller入参为Date date时还是可用springMvc自动转换的。但如果请求参数为date=2021-02-22,就需自定义类型转换器了。
com.kdy.converter包下创建DateConverter类
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String dateStr) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try{
date = sdf.parse(dateStr);
}catch (ParseException e){
e.printStackTrace();
}
return date;
}
}
spring-mvc.xml中实例化这个转换器工厂的bean,并注入这个自定义转换器实例
且spring-mvc.xml中spring-mvc注解驱动需要配置onversion-service为这个bean的id
resource下的spring-mvc.xml内容如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<!--Controller的组件扫描-->
<context:component-scan base-package="com.kdy"></context:component-scan>
<!--配置内部资源视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/jsp"></property><!--前缀-->
<property name="suffix" value=".jsp"></property><!--后缀-->
</bean>
<!--声明springMvc请求参数为date=2021-02-22时controller入参为Date date的类型转换器
1.定义这个bean
2.在springMvc注解驱动中传递这个转换器的bean的id <mvc:annotation-driven conversion-service="conversionService"/> -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.kdy.converter.DateConverter"></bean>
</list>
</property>
</bean>
<!--注解驱动,顶替配置的处理器映射器和适配器,集成了jackson,可Controller资源方法返回字为对象User时,自动转为json-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!--这里配置springMvc的js静态资源放行-->
<mvc:resources mapping="/js/**" location="/js/"/>
</beans>
com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {
/*
* 获取日期类型参数,如果是请求参数为date=2021/02/22即可springMvc子自动类型转换成controller中的入参Date date
* 但如果是请求参数为date=2021-02-22格式需要通过配置的自定义转换器类com.kdy.converter的DateConverter和spring-mvc.xml中配置的转换器并使的springMvc注解驱动配置该转换器
* 访问 http://localhost:8080/SpringMvcModule/user/quick?date=2021-02-22
* */
@RequestMapping("/quick")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save(Date date) {
System.out.println(date);
}
}
SpringMvc获得Servlet相关API
只需在controller的方法入参中传递HttpServletRequest、HttpServletResponse、HttpSession即可
@Controller
@RequestMapping("/user")
public class UserController {
/*
* springMvc获得Servlet相关API
* */
@RequestMapping("/quick")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
System.out.println(request);
System.out.println(response);
System.out.println(session);
}
}
SpringMvc获取请求头
@RequestHeader获得请求头信息,相当于web里的req.getHeader(name)
@CookieValue参数获得指定的Cookie的值
@Controller
@RequestMapping("/user")
public class UserController {
/*
* springMvc获取请求头@RequestHeader
* */
@RequestMapping("/quick")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save(@RequestHeader("Referer") String referer) {
System.out.println(referer);
}
/* springMvc获取请求头@RequestHeader
* @RequestHeader参数
* value请求头名称
* required是否必须请携带此请求头 不写默认为true
* */
@RequestMapping("/quick2")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save2(@RequestHeader(value = "User-Agent",required = false) String user_agent) {
System.out.println(user_agent);
}
/*
* springMvc获取请求头@CookieValue
* @CookieValue参数获得指定的cookie的值,即请求头里Cookie的值有很多个分号分开的key:value,这里获取指定的。
* value请求头名称
* required是否必须请携带此请求头 不写默认为true
* */
@RequestMapping("/quick3")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save3(@CookieValue("JSESSIONID") String jsessionId) {
System.out.println(jsessionId);
}
}
SpringMvc获取文件类型的参数--文件上传
客户端表单文件上传三要数
表单项设置type="file" 表单提交方式设置为post
加上enctype="multipart/form-data",即设置enctype属性为多部分表单形式
在webapp的jsp目录创建uploadFile.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>uploadFile</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/quick" method="post"
enctype="multipart/form-data">
名称<input type="text" name="name"><br/>
文件<input type="file" name="upload"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
文件上传原理:
enctype默认="application/x-www-form-urlencoded"这时form表单正文内容格式为key=value&key=value&key=value,req.getParameter()可用使用。
将enctype设置="Mutilpart/form-data"时,请求正文部分变成多部分形式如下:
------------------7de1a433602ac----------
Content-Disposition:form-date;name="name"
zhangsan
------------------7de1a433602ac----------
Content-Disposition:form-data;name="file"
filename="C:\Users\muzimoo\Desktop\文件上传.txt"
Content-Type:text/plain
aaa(txt内容)
bbb(txt内容)
------------------7de1a433602ac----------
这时req.getParameter()将失效。
在web阶段,我们使用阿帕奇的FileUpload插件进行上传文件,在springmvc中也封装了FileUpload插件。
环境准备
导入坐标:commons-fileupload、commons-io
配置文件上传解析器sprinv-mvc.xml中配置“multipartyResolver”
导入坐标
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
在spring-mvc.xml中配置文件上传解析器
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--上传文件的编码类型-->
<property name="defaultEncoding" value="UTF-8"/>
<!--上传文件总大小,最大限制,单位byte-->
<property name="maxUploadSize" value="5242800"/>
<!--上传单个文件大小,最大限制,单位byte-->
<property name="maxUploadSizePerFile" value="5242800"/>
</bean>
单文件上传
form表单见上webapp的jsp目录创建uploadFile.jsp
com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {
/*
* springMvc获取单文件参数,单文件上传
* jsp/uploadFile.jsp提交post请求且type="file"且enctype="multipart/form-data"到本servlet
* */
@RequestMapping("/quick")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save(String name, MultipartFile upload) throws IOException {
System.out.println(name);
System.out.println(upload);
//对文件进行保存,使用transferTo()方法进行保存到服务器或我们本地硬盘上
String originalFilename = upload.getOriginalFilename();
upload.transferTo(new File("D:\\img\\"+originalFilename));
}
}
访问http://localhost:8080/SpringMvcModule/jsp/uploadFile.jsp
多文件上传方式1
webapp的jsp目录创建uploadFile.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>uploadFile</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/quick" method="post"
enctype="multipart/form-data">
名称<input type="text" name="name"><br/>
文件1<input type="file" name="uploadFile1"><br/>
文件2<input type="file" name="uploadFile2"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {
/*
* springMvc获取文件参数,多文件上传
* jsp/uploadFile.jsp提交post请求且type="file"且enctype="multipart/form-data"到本servlet
* */
@RequestMapping("/quick")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save(String name, MultipartFile uploadFile1, MultipartFile uploadFile2) throws IOException {
System.out.println(name);
//对文件进行保存,使用transferTo()方法进行保存到服务器或我们本地硬盘上
String originalFilename1 = uploadFile1.getOriginalFilename();
uploadFile1.transferTo(new File("D:\\img\\"+originalFilename1));
String originalFilename2 = uploadFile2.getOriginalFilename();
uploadFile2.transferTo(new File("D:\\img\\"+originalFilename2));
}
}
多文件上传方式2
webapp的jsp目录创建uploadFile.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>uploadFile</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/quick" method="post"
enctype="multipart/form-data">
名称<input type="text" name="name"><br/>
文件1<input type="file" name="uploadFile"><br/>
文件2<input type="file" name="uploadFile"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {
/*
* springMvc获取文件参数,多文件上传
* jsp/uploadFile.jsp提交post请求且type="file"且enctype="multipart/form-data"到本servlet
* */
@RequestMapping("/quick")
@ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
public void save(String name, MultipartFile[] uploadFile) throws IOException {
System.out.println(name);
for (MultipartFile file:uploadFile) {
String originalFilename = file.getOriginalFilename();
file.transferTo(new File("D:\\img\\"+originalFilename));
}
}
}