学习地址
https://www.bilibili.com/video/BV1GE411d7KE
我的代码地址:https://gitee.com/Adger_world/spring
SpringMVC是什么
SpringMVC是目前主流的实现MVC设计模式的框架,是Spring框架的分支项目,以SpringIOC容器为基础,并利用容器的特性简化他的配置,SpringMVC相当于Spring的子模块,可以很好的与Spring结合起来进行开发,是JavaWeb必须要掌握的开发框架
什么是MVC设计模式
MVC设计模式不仅存在于Java应用程序当中,开始是起立于桌面应用程序的,一种软件设计典范
- Model(模型)用来映射数据库字段。
- View(视图)用来显示数据。
- Controller(控制器)服务器端程序的入口
最典型的MVC就是JSP + servlet + javabean的模式,初学者很容易把JSP作为前端技术来讲,其实JSP的本质就是Servlet,是Java Server Page从JSP全名称就可以看出来,属于后端的技术
SprngMVC核心组件
-
DispatcherServlet
前置控制器 是整个流程控制的核心,控制其他组件的执行,进行统一调度,降低组件之间的耦合性,核心组件 -
Handler
处理器,完成具体的业务逻辑,相当于Servlet或者Action -
HandlerMapping
DispatcherServlet接受到用户发过来的请求之后,通过HandlerMapping将不同的请求映射到Handler -
HandlerInterceptor
处理器,拦截器,是一个接口,如果需要完成一些拦截处理,那么就可以实现这个接口 -
HandlerExcutionChain
处理器执行链,包括两部分内容,Handler 和 HandlerInterceptor -
HandlerAdapter 处理器适配器,Handler执行业务方法之前,需要进行一系列的操作,包括表单数据的验证、数据类型的转换、将表单数据封装到JavaBean当中等,这些操作都由HandlerAdapter完成,开发者只需要将注意力集中在业务逻辑的处理上。DispatcherServlet通过HandlerAdapter执行不同的Handler。
-
ModelAndView
装载了模型数据,和视图信息,作为Handler的处理结果,返回给DispatcherServlet -
ViewResolver
试图解析器,DispatcherServlet通过它将逻辑视图解析为物理视图,什么是逻辑视图:ModelAndView的时候还是逻辑试图,最终要渲染能看到的界面,物理视图
SpirngMVC工作流程
- 客户端请求被DispatcherServlet接受
- 根据HandlerMapping映射到Handler
- 生成Handler和HandlerInteceptor
- Handler和HandlerInteceptor以HandlerExcutionChain的形式统一返回给DispatcherServlet
- DispatcherServlet通过HandlerAdapter调用Handler的方法完成业务逻辑的处理
- Handler返回一个ModelAndView对象给DispatcherServlet
- DispatcherServlet将获取的ModelAndView对象传给ViewResolver视图解析器,将逻辑视图解析为物理视图
- ViewResolver返回一个view给DispatcherServlet
- DispatcherServlet根据View进行视图渲染(将模型数据填充到视图中)
- DispatcherServlet将渲染后的结果响应给客户端
SpringMVC的特点
- 国际化支持 什么是国际化 就是 在页面实现多国语言切换
- 面向接口编程
- 分离View层的实现
- 提供大量的控制器接口和实现类
- 灵活配置
快速入门
这里使用的是Maven项目构建工具,注意选中骨架就可以了
仓库配置,点击Finish就可以了
等待项目生成
可以打开工程目录,可以看出,不是满足maven的结构,自己需要手动创建Java文件夹跟resources文件夹,在2020版本的idea中已经优点小变化了,会跟你检测到
- 导入依赖,相当于添加Jar包
<!-- Spring 最新稳定版本-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
- 在web.xml中配置DispatcherServlet,这是一个Servlet,所以需要配在web.xml中,在JavaWeb阶段,每写一个servlet,web.xml就有一个servlet的配置对吧
这里的web.xml头版本是3.1还是几忘记了
还需要让DispatcherServlet读取自己的配置文件
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<!-- 自定义servlet名字 -->
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 读取配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- classpath指的是resources根目录 -->
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<!-- 必须跟上面一样 -->
<servlet-name>DispatcherServlet</servlet-name>
<!-- 拦截所有请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- SpringMVC.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<!-- 自动扫描 -->
<context:component-scan base-package="club.adger">
</context:component-scan>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
建立相同结构的包名
package club.adger.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.PrintStream;
/**
* Created with IntelliJ IDEA.
* * @Auther: Adger
* @Date: 2020/08/19/16:37
* @Controller 交给IOC容器管理,同时具备了控制器的功能
*/
@Controller
public class HelloHandler {
@RequestMapping("/index")
public String index(){
final PrintStream out = System.out;
out.println("执行了index请求...");
return "index";
}
}
配置tomcat运行
SpringMVC注解描述
-
@RequestMapping
SpringMVC通过@ResquestMapping 注解将URL请求与业务方法映射,在类上可以添加,在方法上也可以添加,在类的定义处添加的话,就相当于客户端(浏览器)多一层访问路径 -
@Controller
@Controller在类的定义处添加,该类交给IOC容器管理(结合springmvc.xml中的配置自动扫描结合使用),使其成为一个控制器,就可以接受客户端请求了
最基础的配置
package club.adger.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.PrintStream;
/**
* Created with IntelliJ IDEA.
* * @Auther: Adger
* @Date: 2020/08/19/16:37
* @Controller 交给IOC容器管理,同时具备了控制器的功能
*/
@Controller
@RequestMapping("/hello")
public class HelloHandler {
@RequestMapping("/index")
public String index(){
final PrintStream out = System.out;
out.println("执行了index请求...");
return "index";
}
}
- @RequestMapping 相关参数
value指定URL实际请求的地址,是@RequestMapping的默认值
@RequestMapping("/index")
public String index(){
final PrintStream out = System.out;
out.println("执行了index请求...");
return "index";
}
上述写法跟下面一样
@RequestMapping(value = "/index")
public String index(){
final PrintStream out = System.out;
out.println("执行了index请求...");
return "index";
}
- method:指定请求的method类型。Get、Post、Put、Delete
只能被Get请求访问,如果去掉Get和post请求都可以接受
@RequestMapping(value = "/index",method = RequestMethod.GET)
public String index(){
final PrintStream out = System.out;
out.println("执行了index请求...");
return "index";
}
- params:指定请求中必须包含某些参数。否则无法访问
/**
* params中是多个参数就用 {}
*
* @return
*/
@RequestMapping(value = "/index",method = RequestMethod.GET,params = {
"id","name"})
public String index(){
final PrintStream out = System.out;
out.println("执行了index请求...");
return "index";
}
如果浏览器Get请求没有参数直接访问会出现http状态码400错误
现在随便给这两个参数值。发现成功
http://localhost:8080/hello/index?id=1&name=Adger
参数名字必须一样。值无所谓
如果固定死的情况下,值就不能随便填写,比如下面代码的情况。id必须为1
/**
* params中是多个参数就用 {}
*
* @return
*/
@RequestMapping(value = "/index",method = RequestMethod.GET,params = {
"id=1","name"})
public String index(){
final PrintStream out = System.out;
out.println("执行了index请求...");
return "index";
}
如果id不是1,就发生400错误
变成1就能访问成功
http://localhost:8080/hello/index?id=1&name=Adger
但是一般的话不会像上面这么写。而是获取这个从客户端传过来的值
@RequestMapping(value = "/index",method = RequestMethod.GET,params = {
"id","name"})
public String index(int id){
final PrintStream out = System.out;
//打印输出id值
out.println(id);
out.println("执行了index请求...");
return "index";
}
http://localhost:8080/hello/index?id=1&name=Adger
浏览器发送请求,可以看到已经收到并打印出来
注意浏览器的参数名必须跟java代码中的参数必须一样,不然报错,名字一样的话,SpringMVC会帮你自动装填
如果想要不一样的话,可以加上@RequestParam注解
@RequestMapping(value = "/index",method = RequestMethod.GET,params = {
"id","name"})
public String index(@RequestParam("id") int i,@RequestParam("name") String n){
final PrintStream out = System.out;
//打印输出id值和name
out.println(i);
out.println(n);
out.println("执行了index请求...");
return "index";
}
客户端发送请求,http://localhost:8080/hello/index?id=1&name=Adger
发现成功
SpringMVC支持RESTful风格的URL
什么是RESTful风格的URL
是互联网一种架构的形式,直观的能看出接口请求
传统 HTTP 类型:http://localhost:8080/hello/index?id=1&name=Adger
REST风格类型:http://localhost:8080/hello/index/1/Adger
如下面代码RESTful风格的URL
/**
* @PathVariable 代表浏览器地址输入 与下面参数 绑定
* @param id
* @param name
* @return
*/
@RequestMapping("/rest/{id}/{name}")
public String rest(@PathVariable("id") int id,@PathVariable("name") String name){
System.out.println("id"+id+"\t"+name);
return "index";
}
测试访问:http://localhost:8080/hello/rest/1/Adger
发现成功
SpringMVC映射Cookie
什么是Cookie
就是客户端的一个文本文件,保存了用户的一些私人记录
SpringMVC可以直接取出Cookie,实际开发中用的不多
@RequestMapping("/cookie")
public String cookie(@CookieValue(value = "JSESSIONID") String sessionId){
System.out.println(sessionId);
return "index";
}
浏览器访问:http://localhost:8080/hello/cookie
SpringMVC绑定JavaBean
SpringMVC会根据请求参数名和JavaBean的属性名进行关联,自动为对象填充属性值,同时支持级联属性,级联属性也就是,对象中的对象比如,Address address
这里新建的一个包,entity,放实体类的,加入lombok简化实体类,当加入字段的时候就不需要重新生成get和set方法和toString了
package club.adger.entity;
import lombok.Data;
/**
* Created with IntelliJ IDEA.
*
* @Auther: Adger
* @Date: 2020/08/21/20:53
*/
@Data
public class User {
private long id;
private String name;
}
从这里可以看出他的set和get方法等
编写一个页面
<%--
Created by IntelliJ IDEA.
User: Adger
Date: 2020/8/21
Time: 20:59
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/hello/save" method="post">
<%-- 注意这里的 name 属性值 不能随便填 必须是 你的实体类的属性名 才能封装到 JavaBean中去 --%>
用户名id: <input type="text" name="id"><br>
用户名: <input type="text" name="name"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
后端入口编写
这里直接写实体类对象
@RequestMapping(value = "/save",method = RequestMethod.POST)
public String save(User user){
System.out.println(user);
return "index";
}
发现跳转
浏览器直接访问页面测试:http://localhost:8080/register.jsp
这里是没有输入中文的,如果输入中文就会乱码,只需要加一个过滤器就可以了,没有加的情况下测试
发现乱码
解决:在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>
重启测试
发现成功
级联绑定
新建一个实体类
package club.adger.entity;
import lombok.Data;
/**
* Created with IntelliJ IDEA.
*
* @Auther: Adger
* @Date: 2020/08/21/21:15
*/
@Data
public class Address {
private String address;
}
在原来的register.jsp中多添加个输入框
<%--
Created by IntelliJ IDEA.
User: Adger
Date: 2020/8/21
Time: 20:59
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/hello/save" method="post">
<%-- 注意这里的 name 属性值 不能随便填 必须是 你的实体类的属性名 才能封装到 JavaBean中去 --%>
用户名id: <input type="text" name="id"><br>
用户名: <input type="text" name="name"><br>
<%-- 第一个address是 user实体类中的,第二个是 Address对象的 属性值 --%>
用户地址: <input type="text" name="address.address"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
浏览器测试访问:http://localhost:8080/register.jsp
发现成功
JSP页面的转发和重定向
转发和重定向是什么:就是页面之间的跳转的两种的不同方式,转发是服务器端跳转,重定向是客户端的跳转,区别:转发地址栏不会改变,重定向地址栏改变,转发是一次请求,重定向是两次请求,转发不会丢失数据,而重定向会
SpringMVC默认是以转发的形式响应jsp的
- 转发
新写一个入口
@RequestMapping("/forward")
public String forward(){
// 相当于 return "index";
return "forward:/index.jsp";
}
浏览器测试访问:http://localhost:8080/hello/forward
发现地址栏是没有变化的
- 重定向
新写一个入口
@RequestMapping("/redirect")
public String redirect(){
//转发跟重定向像 这么 写的话 必须加后最 不然找不到的
return "redirect:/index.jsp";
}
浏览器测试访问:http://localhost:8080/hello/redirect
测试发现浏览器地址栏变化
SpringMVC 数据绑定
数据绑定:在后端的业务方法中直接获取客户端的HTTP请求中的参数,将请求参数映射到业务方法中的形参中
SpringMVC中的数据绑定的工作是由HandlerAdapter来完成的
- 基本数据类型的绑定
这段代码
package club.adger.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Created with IntelliJ IDEA.
*
* @Auther: Adger
* @Date: 2020/08/21/21:44
*/
@Controller
@RequestMapping("/data")
public class DataBindHandler {
@RequestMapping("/baseType")
public String baseType(int id){
return id+"";
}
}
这里不希望直接返回jsp页面,而是客户端发过来的请求直接返回id值,这样写的话,直接当成逻辑视图来解析
浏览器测试访问:http://localhost:8080/data/baseType?id=1
发现SpringMVC直接当成逻辑视图解析了
怎么解决呢,写上@ResponseBody注解
package club.adger.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* Created with IntelliJ IDEA.
* * @Auther: Adger
* @Date: 2020/08/21/21:44
*/
@Controller
@RequestMapping("/data")
public class DataBindHandler {
@RequestMapping("/baseType")
@ResponseBody
public String baseType(int id){
return id+"";
}
}
浏览器测试访问:http://localhost:8080/data/baseType?id=1
@RequestBody 表示SpringMVC会直接将业务方法的返回值响应给客户端,如果不加@RequestBody注解,SpringMVC会将业务方法的返回值传递给DispatcherServlet再由DispatcherServlet调用ViewResolver对返回值进行解析,映射到一个jsp资源
- 包装类
为什么使用包装类:包装类自带了默认值,就比如下面这种情况,如果什么都不传的话:http://localhost:8080/data/baseType,就会发生500错误
@RequestMapping("/packageType")
@ResponseBody
public String packageType(Integer id){
return id+"";
}
浏览器访问测试:http://localhost:8080/data/packageType
包装类可以接收null,当HTTP请求没有参数时,使用包装类定义形参的数据类型,程序不会抛出异常
下图代码
@RequestMapping("/packageType")
@ResponseBody
public String packageType(@RequestParam(value = "num",required = false,defaultValue = "0") Integer id){
return id+"";
}
@RequestParam注解里面的属性值解释
- value
value="num"代表将HTTP请求中名为num的参数赋给形参id - required
required=true代表必填,false代表不必, - defaultValue
defaultValue = "0"如果HTTP请求中没有参数则默认值为0
数组
@RequestMapping("/array")
@ResponseBody
public String array(String[] name){
String s = Arrays.toString(name);
return s;
}
在浏览器输入测试地址:http://localhost:8080/data/array?name=adger&name=wangwu
发现成功
简化@ResponseBody
从这张图能看出来,如果写一个就需要@ResponseBody,简化如下代码
package club.adger.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
/**
* Created with IntelliJ IDEA.
*
* @Auther: Adger
* @Date: 2020/08/21/21:44
*/
@RestController
@RequestMapping("/data")
public class DataBindHandler {
@RequestMapping("/baseType")
public String baseType(int id){
return id+"";
}
@RequestMapping("/packageType")
public String packageType(@RequestParam(value = "num",required = false,defaultValue = "0") Integer id){
return id+"";
}
@RequestMapping("/array")
public String array(String[] name){
String s = Arrays.toString(name);
return s;
}
}
@RestController:Controller里面的方法都是以Rest形式返回,如果是提供数据的就可以用@RestController,如果需要视图,就不需要用@RestController,简单来说就是@RestController返回了Model,而@Controller返回了ModelAndView
@RestController
@RequestMapping("/data")
public class DataBindHandler {
@RequestMapping("/baseType")
public String baseType(int id){
return id+"";
}
}
等于
@Controller
@RequestMapping("/data")
public class DataBindHandler {
@RequestMapping("/baseType")
@ResponseBody
public String baseType(int id){
return id+"";
}
}
集合
SpirngMVC不支持List类型的直接转换,需要对List类型集合进行包装。
新建一个实体类
package club.adger.entity;
import lombok.Data;
import java.util.List;
/**
* Created with IntelliJ IDEA.
*
* @Auther: Adger
* @Date: 2020/08/23/15:12
*/
@Data
public class UserList {
private List<User> users;
}
新写一个控制方法
@RequestMapping("/list")
public String list(UserList userList){
StringBuffer stringBuffer = new StringBuffer();
for (User user:userList.getUsers()) {
stringBuffer.append(user);
}d
return stringBuffer.toString();
}
新建一个jsp页面
<%--
Created by IntelliJ IDEA.
User: Adger
Date: 2020/8/23
Time: 15:19
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%-- 这些封装到User对象中去,后台用的UserList参数接受,实体类是List<User> 所以可以这样封装 --%>
<form action="/data/list" method="post">
用户1编号: <input type="text" name="users[0].id"><br>
用户1名称:<input type="text" name="users[0].name"><br>
用户2编号: <input type="text" name="users[1].id"><br>
用户2名称:<input type="text" name="users[1].name"><br>
用户3编号: <input type="text" name="users[2].id"><br>
用户3名称:<input type="text" name="users[2].name"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
浏览器访问:http://localhost:8080/addList.jsp
输入测试数据提交,有中文发现乱码
打个断点调试,发现return 那里还是中文的,那就是服务器端返回前端的时候乱码
在以前的Web工程能直接使用servlet因为tomcat有,而maven工程是不会依赖
这里用servlet编码响应格式没有效,直接通过配置文件的方式去配
SpringMVC.xmll配置文件改写
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<mvc:annotation-driven>
<!-- 消息转换器 -->
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 自动扫描 -->
<context:component-scan base-package="club.adger">
</context:component-scan>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
重新测试:http://localhost:8080/addList.jsp
发现成功
处理@ResponseBody中文乱码,可以直接在SpirngMVC配置消息转换器
<mvc:annotation-driven>
<!-- 消息转换器 -->
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
map
自定义封装类
package club.adger.entity;
import lombok.Data;
import java.util.Map;
/**
* Created with IntelliJ IDEA.
*
* @Auther: Adger
* @Date: 2020/08/24/16:37
*/
@Data
public class UserMap {
private Map<String,User> users;
}
业务方法
@RequestMapping("/map")
public String map(UserMap userMap){
StringBuffer stringBuffer = new StringBuffer();
// map集合遍历跟List集合不一样 遍历key值
for (String key : userMap.getUsers().keySet()){
User user = userMap.getUsers().get(key);
stringBuffer.append(user);
}
return stringBuffer.toString();
}
Jsp
<%--
Created by IntelliJ IDEA.
User: Adger
Date: 2020/8/24
Time: 16:43
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/data/map" method="post">
<%-- 这里[] 中的名字 随便定义 但是 服务器端就必须 按照这种名字来取 --%>
用户1编号: <input type="text" name="users['a'].id"><br>
用户1名称:<input type="text" name="users['a'].name"><br>
用户2编号: <input type="text" name="users['b'].id"><br>
用户2名称:<input type="text" name="users['b'].name"><br>
用户3编号: <input type="text" name="users['c'].id"><br>
用户3名称:<input type="text" name="users['c'].name"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
浏览器测试访问http://localhost:8080/addMap.jsp
注意点:前端的数据类型要和后端的数据类型一致
发现成功
JSON
客户端发生JSON格式的数据,直接通过SpringMVC绑定到业务方法的形参中
用Ajax发送请求,加上Jquery,我在web-app目录下新建了一个文件夹叫,js,把jquery引入进来
新建一个json.jsp文件
<%--
Created by IntelliJ IDEA.
User: Adger
Date: 2020/8/24
Time: 16:56
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<%-- 引入jquery --%>
<script src="js/jquery.min-3.5.js"></script>
</head>
<body>
<script>
$(function () {
alert(123)
})
</script>
</body>
</html>
启动tomcat测试访问这个页面看jquery环境有没有成功,如果alert就成功,浏览器输入:http://localhost:8080/json.jsp
发现 $ 找不到问题,其实这是SpringMVC拦截了
前置控制器拦截了所有请求,包括静态资源
可以在SpringMVC配置文件配置,也可以在web.xml中配置,不由DispatcherServlet控制,交给默认的servlet
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
浏览器再测试访问:http://localhost:8080/json.jsp
发现成功
发送ajax请求,表单是发送不了的
<%--
Created by IntelliJ IDEA.
User: Adger
Date: 2020/8/24
Time: 16:56
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<%-- 引入jquery --%>
<script src="js/jquery.min-3.5.js"></script>
</head>
<body>
<script>
/**
* json数据格式
*/
$(function () {
var user = {
"id":1,
"name":"张三"
};
$.ajax({
url:"data/json",//地址
data:JSON.stringify(user),//把user对象转换为json数据格式
type:"POST",//请求方式
contentType:"application/json;charset=UTF-8",//因为有 中文设置编码
dataType:"JSON",//返回的数据格式
success:function (data) {
alert(data.id + "--" + data.name)
}
})
})
</script>
</body>
</html>
后台的业务方法
/**
* 如果你是json数据对象 需要加@RequestBody 一个 是@ResponseBody响应 一个是接受
* @param user
* @return
*/
@RequestMapping("/json")
public User json(@RequestBody User user){
System.out.println(user);
return user;
}
浏览器访问测试:http://localhost:8080/json.jsp
发现出错
后台也没有进入
借助阿里巴巴的fastJson解析json数据,还需再SpringMVC.xml中配置解析
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.72</version>
</dependency>
SpringMVC.xml配置,我发现我这个版本的FastJsonHttpMessageConverter已经去掉了![
<mvc:annotation-driven>
<!-- 消息转换器 -->
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/html;charset=UTF-8"></property>
</bean>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"></bean>
</mvc:message-converters>
</mvc:annotation-driven>
发现数据弹出
SpringMVC的json和javaBean的转换需要借助于fastjson
SpringMVC的模型数据解析
SpringMVC很重要的一项工作就是再控制器获取模型数据,并且返回给客户端,也就是在jsp页面展示模型数据,jsp也就是使用el表达式从域对象中获取出来
Jsp的四大作用域内置对象也就是可以直接使用的回顾
-
pageContext
-
request
-
session
-
application
上面从小到大,模型数据的绑定是由ViewReslover来玩成的,在实际开发中,我们需要先添加模型数据,在交给ViewResolver来绑定
SpringMVC提供一下几种方式来添加模型数据 -
Map
-
Model
-
ModelAndView
-
@SessionAttribute
-
@ModelAttribute
map
新建一个ViewHandler,业务方法如下
package club.adger.controller;
import club.adger.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;
/**
1. Created with IntelliJ IDEA.
2. 3. @Auther: Adger
4. @Date: 2020/08/24/19:47
5. 因为是视图 所以 用的是Controller 不需要 json数据现在
*/
@Controller
@RequestMapping("/view")
public class ViewHandler {
/**
* 因为 直接 返回 一个视图没什么作用的 需要 放入 map 中 从view 页面 中获取 模型数据
* @param map
* @return
*/
@RequestMapping("/map")
public String map(Map<String,User> map){
User user = new User();
user.setId(1);
user.setName("Adger");
map.put("user",user);
return "view";
}
}
新建一个View.jsp的页面,作为视图
<%--
Created by IntelliJ IDEA.
User: Adger
Date: 2020/8/24
Time: 19:54
To change this template use File | Settings | File Templates.
--%>
<%--
isELIgnored 是否 忽略 el表达式 改为 False
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${
requestScope.user}
</body>
</html>
浏览器启动测试:http://localhost:8080/view/map
发现成功
Model
业务方法如下
@RequestMapping("/model")
public String model(Model model){
User user = new User();
user.setId(1);
user.setName("Adger");
model.addAttribute("user",user);
return "view";
}
视图页面不动,浏览器访问:http://localhost:8080/view/model
ModelAdnView
业务方法如下
@RequestMapping("/modelAndView")
public ModelAndView modelAndView(){
User user = new User();
user.setId(1);
user.setName("Adger");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user",user);
modelAndView.setViewName("view");
return modelAndView;
}
视图还是不变
浏览器访问测试:http://localhost:8080/view/modelAndView
发现成功
另外一种方式
@RequestMapping("/modelAndView2")
public ModelAndView modelAndView2(){
User user = new User();
user.setId(1);
user.setName("Adger");
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user",user);
View view = new InternalResourceView("/view.jsp");
modelAndView.setView(view);
return modelAndView;
}
等于上第一个的
浏览器访问测试:http://localhost:8080/view/modelAndView2
第三种形式,这三种其实都是一样的
@RequestMapping("/modelAndView3")
public ModelAndView modelAndView3(){
User user = new User();
user.setId(1);
user.setName("Adger");
ModelAndView modelAndView = new ModelAndView("view");
modelAndView.addObject("user",user);
return modelAndView;
}
浏览器访问测试:http://localhost:8080/view/modelAndView3
发现成功
第四种方式
@RequestMapping("/modelAndView4")
public ModelAndView modelAndView4(){
User user = new User();
user.setId(1);
user.setName("Adger");
ModelAndView modelAndView = new ModelAndView("view");
modelAndView.addObject("user",user);
return modelAndView;
}
浏览器访问测试:http://localhost:8080/view/modelAndView4
第五种方式
@RequestMapping("/modelAndView5")
public ModelAndView modelAndView5(){
User user = new User();
user.setId(1);
user.setName("Adger");
Map<String, User> map = new HashMap<>();
map.put("user",user);
ModelAndView modelAndView = new ModelAndView("view",map);
return modelAndView;
}
浏览器访问测试:http://localhost:8080/view/modelAndView5
发现成功
第6种方式
@RequestMapping("/modelAndView6")
public ModelAndView modelAndView6(){
User user = new User();
user.setId(1);
user.setName("Adger");
Map<String, User> map = new HashMap<>();
map.put("user",user);
View view = new InternalResourceView("/view.jsp");
ModelAndView modelAndView = new ModelAndView(view,map);
return modelAndView;
}
浏览器访问测试:http://localhost:8080/view/modelAndView6
发现成功
第七种方式
@RequestMapping("/modelAndView7")
public ModelAndView modelAndView7(){
User user = new User();
user.setId(1);
user.setName("Adger");
//后面两个参数是 你到 key value
ModelAndView modelAndView = new ModelAndView("view","user",user);
return modelAndView;
}
浏览器访问测试:http://localhost:8080/view/modelAndView7
第八种
@RequestMapping("/modelAndView8")
public ModelAndView modelAndView8(){
User user = new User();
user.setId(1);
user.setName("Adger");
View view = new InternalResourceView("/view.jsp");
//后面两个参数是 你到 key value
ModelAndView modelAndView = new ModelAndView(view,"user",user);
return modelAndView;
}
浏览器访问测试:http://localhost:8080/view/modelAndView8
使用原生的方式
先导入servlet-api的依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
写后台业务方法
@RequestMapping("/request")
public String request(HttpServletRequest httpServletRequest){
User user = new User();
user.setId(1);
user.setName("Adger");
httpServletRequest.setAttribute("user",user);
return "view";
}
浏览器测试访问:http://localhost:8080/view/request
发现成功
@ModelAttribute
这个注解的使用方法
- 定义一个方法,改方法专门用来返回要填充到模型数据中的对象
- 业务方法无需处理数据模型,只需要返回视图
@ModelAttribute
public User getUser(){
User user = new User();
user.setId(1);
user.setName("Adger");
return user;
}
@RequestMapping("/ModelAttribute")
public String modelAttribute(){
return "view";
}
浏览器测试访问:http://localhost:8080/view/ModelAttribute
发现成功