资源已上传-离线文档 spring-framework-5.3.8\docs\reference\html
1.SpringMVC
从易用性, 效率上, 比曾经流行的Struts2
更好
2.SpringMVC
是WEB
层框架 [解读: SpringMVC
接管了Web
层组件, 比如控制器, 视图, 视图解析, 返回给用户的数据格式, 同时支持MVC
的开发模式/开发架构]
3.SpringMVC
通过注解, 让POJO
成为控制器, 不需要继承类或者实现接口
4.SpringMVC
采用低耦合的组件设计方式, 具有更好地扩展性和灵活性
5.支持REST
格式的URL
请求
6.SpringMVC
是基于Spring
的, 也就是SpringMVC
是在Spring
基础上的. SpringMVC
的核心包是 spring-web-5.3.8.jar, spring-webmvc-5.3.8.jar
1.Spring MVC
只是Spring
处理WEB
层请求的一个模块/组件, Spring MVC
的基石是Servlet[Java WEB]
2.Spring Boot
是为了简化开发者的使用, 推出的封神框架(约定优于配置, 简化了Spring
的配置流程), SpringBoot
包含很多组件/框架. Spring
就是最核心的内容之一, 也包含Spring MVC
3.它们大概的关系是: SpringBoot > Spring > Spring MVC
1.创建springmvc web
工程, 导入jar
包 新建javaweb项目, 参考
2.创建src/applicationContext-mvc.xml
容器文件
3.配置web.xml
<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">
<servlet>
<servlet-name>springDispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext-mvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springDispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
4.web目录新建login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录页面title>
head>
<body>
<%--后面再填写?--%>
<form action="?">
username: <input type="text" name="username"/><br/>
password: <input type="password" name="password"/><br/>
<input type="submit" value="登录">
form>
body>
html>
5.在com.zzw.web
包下新建UserServlet
/*
1.如果我们使用了SpringMVC, 在一个类上标识@Controller
2.表示将该类视为一个控制器, 注入到容器
3.比原生servlet开发要简化很多
*/
@Controller
public class UserServlet {
//编写方法, 响应用户的请求
/**
* 解读
* 1. login() 方法是用于响应用户的登录请求
* 2. @RequestMapper(value="/login"), 类似于我们原生Servlet
* 配置的url-pattern, 就是给方法配置一个url映射
* 3. 即当用户在浏览器输入 http://localhost:8080/web工程路径/login 就能够访问到login()
* 4. return "login ok"; 表示返回结果给视图解析器(InternalResourceViewResolver)
* , 视图解析器会根据配置, 来决定跳转到哪个页面
*
*
*
*
*
*
*
* 根据上面配置的 return "login_ok"; 就会转发到 /WEB-INF/pages/login_ok.jsp
*/
@RequestMapping(value = "/login")
public String login() {
System.out.println("login ok...");
return "login_ok";
}
}
6.在web路径/WEB-INF/pages目录
下 新建login_ok.jsp`
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登陆成功title>
head>
<body>
<h1>登陆成功~h1>
body>
html>
7.配置applicationContext-mvc.xml
说明: InternalResourceViewResolver
的父类UrlBasedViewResovler
, 有属性prefix, suffix
<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 https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.zzw.web"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
bean>
beans>
9.配置login.jsp
页面访问路径 参考->web工程路径专题
<body>
<%--
这里需要回顾 javaweb-web工程路径专题
1. action="login" 表示url 是 http://localhost:8080/springmvc/login
前提: 当前页面在web路径下, 相对路径为 http://localhost:8080/springmvc/login.jsp
2. action="/login" 表示url 是 http://localhost:8080/login
--%>
<form action="login">
username: <input type="text" name="username"/><br/>
password: <input type="password" name="password"/><br/>
<input type="submit" value="登录">
form>
body>
1.学习如何搭建一个springmvc
项目, 初步理解springmvc
工作流程
2.这里的UserServlet
需要注解成@Controller
, 我们称之为一个Handler
处理器
3.UserServlet
指定url时, 是可以省略的
4.关于SpringMVC
的DispatcherServlet
的配置文件, 如果不在web.xml
中指定applicationContext-mvc.xml
, 默认在/WEB-INF/springDispatcherServlet-servlet.xml
找这个配置文件 (推荐使用, 做修改, 并完成测试)
查看DispatcherServlet
父类FrameworkServlet
的源码
1)修改web.xml
, 注销init-param
配置节点
<servlet>
<servlet-name>springDispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
这时运行会报错. 因为在WEB-INF目录
下找不到springDispatcherServlet-servlet.xml
文件
2)剪切原applicationContext-mvc.xml
到/WEB-INF
目录下, 文件名为: 你配置的DispatcherServlet
名字-servlet.xml
, 即/WEB-INF/springDispatcherServlet-servlet.xml
运行, 正常.
RequestMapping
注解可以指定控制器/处理器的某个方法的请求的url
1.说明: @RequestMapping
注解可以修饰方法, 还可以修饰类. 当同时修饰类和方法时, 请求的url 就是组合 /类请求值/方法请求值
案例
1.com.zzw.web
包下 新建UserHandler
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
/**
* 1.method=RequestMethod.POST: 表示请求buy目标方法必须是 post
* 2.RequestMethod 四个常用选项 POST, GET, PUT, DELETE[后面会详解]
* 3.SpringMVC 控制器默认支持GET和POST两种方式
*
* buy()方法请求的url: http://ip:port/工程路径/user/buy
* @return
*/
@RequestMapping(value = "/buy", method = RequestMethod.POST)
public String buy() {
System.out.println("购买.");
return "success";
}
}
2.web路径/WEB-INF/pages目录
新建success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>操作成功title>
head>
<body>
<h1>恭喜, 操作成功~h1>
body>
html>
3.web路径
下 新建request.jsp
, 测试
<body>
<%--解读
1. action="user/buy" 对应 url http://localhost:8080/工程路径/user/buy
--%>
<form action="user/buy" method="post">
购买人: <input type="text" name="username"/><br/>
购买量: <input type="password" name="nums"/><br/>
<input type="submit" value="购买">
form>
body>
1.说明: @RequestMapping
可以指定请求方式(post/get/put/delete..
), 请求的方式要和指定的一样, 否则报错.
2.SpringMVC
控制器默认支持GET
和POST
两种方式, 也就是你不指定method
, 可以接收GET
和POST
请求
4.当你明确指定了method
, 则需要按指定方式请求, 否则会报错.
1.param1:
表示请求必须包含名为param1
的请求参数. 比如 params = "bookId"
2.!param1:
表示请求不能包含名为param1
的请求参数. 比如 params = "!bookId"
3.param1 = value1:
表示请求包含名为param1
的请求参数, 且其值必须为value1
. 比如 params = "bookId=100"
4.param1 != value1:
表示请求包含名为param1
的请求参数, 但其值不能为value1
. 比如 params = "bookId!=100"
5.{"param1=value1", "param2"}:
请求必须包含名为param1
, param2
的两个请求参数, 且param1
参数的值必须为value1
. 比如params = {"bookId=100", "price"}
案例
1.修改UserHandler.java
增加方法search
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
/**
* 解读
* 1. params="bookId" 表示请求该目标方法时, 必须给一个bookId参数, 值没有限定
* 2. search(String bookId) 表示请求目标方法时, 携带的bookId=100, 就会将请求携带的 bookId
* 对应的值, 赋给 String bookId
* @param bookId
* @return
*/
@RequestMapping(value = "/find", params = "bookId", method = RequestMethod.GET)
public String search(String bookId) {
System.out.println("查询书籍 bookId=" + bookId);
return "success";
}
}
2.修改request.jsp
<body>
<h1>演示params的使用h1>
<a href="user/find?bookId=100">查询书籍a>
body>
3.操作成功
如果bookId
改为bookIdx
, 报错
细节1:
如果需要有bookId
参数, 并且值为100
. 否则报错.
@RequestMapping(value = "/find", params = "bookId=100", method = RequestMethod.GET)
修改request.jsp
<body>
<h1>演示params的使用h1>
<a href="user/find?bookId=200">查询书籍a>
body>
细节2:
需要有bookId参数, 并且值不为100. 否则报错.
@RequestMapping(value = "/find", params = "bookId!=100", method = RequestMethod.GET)
修改request.jsp
<body>
<h1>演示params的使用h1>
<a href="user/find?bookId=100">查询书籍a>
body>
1.?: 匹配文件名中的一个字符
2.*: 匹配文件名中的任意字符
3.**: 匹配多层路径
4.举例
/user/*/createUser:
匹配/user/aaa/createUser, /user/bbb/createUser
等 URL
/user/**/createUser:
匹配/user/createUser, /user/aaa/bbb/createUser
等 URL
/user/createUser??:
匹配/user/createUseraa, /user/createUserbb
等 URL
案例
1.修改UserHandler.java
增加方法im
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
/**
* 要求: 可以配置 /user/message/aa, /user/message/aa/bb/cc
* @RequestMapping(value="/message/**") 表示可以匹配多层路径
*/
@RequestMapping(value = "/message/**")
public String im() {
System.out.println("发送消息");
return "success";
}
}
2.修改request.jsp
<body>
<hr><h1>演示Ant风格的请求资源方式h1>
<a href="user/message/aa">发送消息1a>
<a href="user/message/aa/bb/cc">发送消息2a>
body>
3.测试成功…
1.@RequestMapping
可以配合@PathVariable
映射URL
绑定的占位符
2.这样就不需要在url
地址上带参数名了, 更加的简洁明了.
案例
1.修改UserHandler.java
增加方法register
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
/**
* 前端页面: 占位符的演示
* (value="/reg/{username}/{userId}"): 表示Kristina=>{username} 300=>{userId}
*
* @return
*/
@RequestMapping(value = "/reg/{username}/{userId}")
public String register(@PathVariable("username") String name,
@PathVariable("userId") int id) {
System.out.println("接收到参数--" + "username=" + name + "--" + "userId=" + id);
return "success";
}
}
2.修改request.jsp
<body>
<hr/><h1>占位符的演示h1>
<a href="user/reg/Kristina/300">占位符的演示a>
body>
3.测试成功…
1.映射的URL
, 不能重复
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
@RequestMapping(value = "/hi")
public String hi() {
System.out.println("hi");
return "success";
}
@RequestMapping(value = "/hi")
public String hi2() {
System.out.println("hi");
return "success";
}
}
启动或重新发布时, 会报错. to { [/user/hi]}: There is already 'userHandler' bean method
2.各种简写的方式
@RequestMapping(value=“/buy”,method=RequestMethod.POST) 等价 @PostMapping(value=“/buy”)
简写方式一览: @GetMapping @PostMapping @PutMapping @DeleteMapping
案例
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
/**
* 5.@PostMapping(value="/buy") 等价 @Request(value="/buy", method=RequestMapping.POST)
* @return
*/
//@RequestMapping(value = "/buy", method = RequestMethod.POST)
@PostMapping(value = "/buy")
public String buy() {
System.out.println("购买.");
return "success";
}
}
测试request.jsp
<body>
<form action="user/buy" method="get">
购买人: <input type="text" name="username"/><br/>
购买量: <input type="password" name="nums"/><br/>
<input type="submit" value="购买">
form>
body>
报错
3.如果我们确定表单或者超链接会提交某个字段数据比如email
, 要求提交的参数名和目标方法的参数名保持一致.
案例
1.修改UserHandler.java
增加方法hello3
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
/**
* hello3(String email) 表示如果我们的请求参数有 email=xx, 就会将传递的值, 赋给String email
* , 要求名称保持一致, 如果不一致, 那么接收不到数据, 而是null
* @param email
* @return
*/
@RequestMapping(value = "/hello3")
public String hello3(String email) {
System.out.println("email=" + email);
return "success";
}
}
2.测试 浏览器地址栏 输入http://localhost:8080/springmvc/user/[email protected]
, 一定要注意提交参数名和后台方法的形参名保持一致, 否则后端接收不到参数
1.熟悉SpringMVC
的执行流程图
2.熟悉@RequestMapping
注解的使用方式
3.编写一个表单, 以Post
的方式提交Computer
信息, 后端编写ComputerHandler
, 可以接收到信息.
代码实现
1.修改request.jsp
<body>
<h1>电脑信息h1>
<form action="?" method="post">
品牌:<input type="text" name="brand"/><br/>
价格:<input type="text" name="price"/><br/>
数量:<input type="text" name="nums"/><br/>
<input type="submit" value="提交">
form>
body>
2.com.zzw.web
包下 新建ComputerHandler
@RequestMapping(value = "/computer")
@Controller
public class ComputerHandler {
//这里一定要注意, info方法的形参名需要和请求的参数名保持一致
@PostMapping(value = "/info", params = {"brand", "price", "nums"})
public String info(String brand, String price, String nums) {
System.out.println("电脑信息--brand=" + brand
+ "--price=" + price + "--nums" + nums);
return "success";
}
}
3.配置页面访问路径
<form action="computer/info" method="post">
1.Postman
是一款功能超级强大的用于发送HTTP
请求的 测试工具.
2.做WEB
页面开发和测试的人员常用工具.
3.创建和发送任何的HTTP
请求(GET/Post/Put/Delete)
官方网站: https://www.postman.com/
文档: https://learning.postman.com/docs/introduction/overview/
下载地址: https://www.postman.com/downloads/.
资料已上传…
1.资料已上传, 下载后右键管理员身份
打开即可安装(非常简单), Postman
不会让你选择安装路径, 会直接安装, 一般安装在系统盘.
2.安装成功, 在桌面上有快捷图标. 双击打开Postman.
●要求:使用Postman
向 http://www.baidu.com
发出get
请求, 得到返回的html
格式数据
调整字体大小: File–Settings
调整页面大小: ctrl
++
, ctrl
+ -
注册账号:
(可选, 不注册不影响使用) 输入邮件, 用户名, 密码
1.创建Http Request
, 如果你已经创建过, 会直接进入Workspace
需求说明: 使用Postman
, 完成UserHandler
方法的请求
1.完成请求
使用Postman测试Controller方法的步骤
1.确定请求的地址 url: http://localhost:8080/springmvc/user/buy
2.请求的方式 -Post
3.确定请求的参数/数据 -无
4.确定Header
有没有特殊的指定 -无
http协议
2.完成请求
使用Postman测试Controller方法的步骤
1.确定请求的地址 url: http://localhost:8080/springmvc/user/find
2.请求的方式 -Get
3.确定请求的参数/数据 -bookId=100
4.确定Header
有没有特殊的指定 -无
3.完成请求
使用Postman测试Controller方法的步骤
1.确定请求的地址 url: http://localhost:8080/springmvc/user/message/aa/bb/cc
2.请求的方式 -Get/Post
3.确定请求的参数/数据 -无
4.确定Header
有没有特殊的指定 -无
4.完成请求
使用Postman测试Controller方法的步骤
1.确定请求的地址 url: http://localhost:8080/springmvc/user/reg/zzw/23
2.请求的方式 -Get/Post
3.确定请求的参数/数据 -无
4.确定Header
有没有特殊的指定 -无
5.完成请求
使用Postman测试Controller方法的步骤
1.确定请求的地址 url: http://localhost:8080/springmvc/user/hello3
2.请求的方式 -Get
3.确定请求的参数/数据 [email protected]
4.确定Header
有没有特殊的指定 -无
1.创建 对应的Http Request
, 放到已有的Collection
2.在Headers
选项页, 增加 Content-Type applicatoin/json
3.因为是Post
请求, 在Body
选项填写Json
数据/Furn
数据
1.创建新的Collection
, 命名为你的名字, 比如 zzwCollection
2.创建多个http request
, 完成对UserHandler
的各个方法的请求
测试1
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
@PostMapping(value = "/buy")
public String buy() {
System.out.println("购买.");
return "success";
}
}
使用Postman测试Controller方法的步骤
1.确定请求的地址 url: http://localhost:8080/springmvc/user/buy
2.请求的方式 -Post
3.确定请求的参数/数据 -无
4.确定Header
有没有特殊的指定 -无
测试2
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
@RequestMapping(value = "/find", params = "bookId=100", method = RequestMethod.GET)
public String search(String bookId) {
System.out.println("查询书籍 bookId=" + bookId);
return "success";
}
}
使用Postman测试Controller方法的步骤
1.确定请求的地址 url: http://localhost:8080/springmvc/user/find
2.请求的方式 -Get
3.确定请求的参数/数据 -bookId=100
4.确定Header
有没有特殊的指定 -无
测试3
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
@RequestMapping(value = "/message/**")
public String im() {
System.out.println("发送消息");
return "success";
}
}
使用Postman测试Controller方法的步骤
1.确定请求的地址 url: http://localhost:8080/springmvc/user/message/aa/bb/cc
2.请求的方式 -Get/Post
3.确定请求的参数/数据 无
4.确定Header
有没有特殊的指定 -无
测试4
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
@RequestMapping(value = "/reg/{username}/{userId}")
public String register(@PathVariable("username") String name,
@PathVariable("userId") int id) {
System.out.println("接收到参数--" + "username=" + name + "--" + "userId=" + id);
return "success";
}
}
使用Postman测试Controller方法的步骤
1.确定请求的地址 url: http://localhost:8080/springmvc/user/reg/star/3000000
2.请求的方式 -Get/Post
3.确定请求的参数/数据 -无
4.确定Header
有没有特殊的指定 -无
测试5
@RequestMapping(value = "/user")
@Controller //UserHandler就是一个处理器/控制器, 会注入到容器
public class UserHandler {
@GetMapping(value = "/hello3")
public String hello3(String email) {
System.out.println("email=" + email);
return "success";
}
}
使用Postman测试Controller方法的步骤
1.确定请求的地址 url: http://localhost:8080/springmvc/user/hello3
2.请求的方式 -Get
3.确定请求的参数/数据 [email protected]
4.确定Header
有没有特殊的指定 -无
●说明
1.REST:
即Representational State Transfer
. (资源)表现层状态转化. 是目前流行的请求方式. 它结构清晰, 很多网站使用.
2.HTTP
协议里面, 四个表示操作方式的动词: GET, POST, PUT, DELETE
, 它们分别对应四种基本操作: GET
用来获取资源, POST
用来新建资源, PUT
用来更新资源, DELETE
用来删除资源
3.实例. 传统的请求方法:
getBook?id=1 GET
delete?id=1 GET
update POST
add POST
4.说明: 传统的url
是通过参数来说明crud
的类型, rest
是通过get/post/put/delete
来说明crud
的类型
●REST
的核心过滤器
1.当前的浏览器只支持post/get
请求, 因此为了得到put/delete
的请求方式需要使用Spring提供的HiddenHttpMethodFilter
过滤器进行转换.
2.HiddenHttpMethodFilter:
浏览器form
表单只支持GET
和POST
请求, 而DELETE
, PUT
等method
并不支持, Spring
添加了一个过滤器, 可以将这些请求转换为标准的http
方法, 使得支持GET, POST, PUT
和DELETE
请求.
3.HiddenHttpMethodFilter
只能对post
请求方式进行转换.
4.这个过滤器需要在web.xml
中配置
需求说明
小明去书店买书, 完成购买书籍的增删改查
1.修改web.xml
, 配置HiddenHttpMethodFilter
<filter>
<filter-name>hiddenHttpMethodFilterfilter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
2.修改springDispatcherServlet-serlvet.xml
添加配置
<mvc:annotation-driven>mvc:annotation-driven>
<mvc:default-servlet-handler/>
3.在web路径
下创建rest.jsp
, 注意引入jquery
, 测试查询/添加/删除/修改
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>rest测试title>
head>
<body>
<h3>Rest风格的crud操作案例h3>
<br/><hr>
<h3>rest风格的url 查询书籍[get]h3>
<a href="?">点击查询书籍a>
<br/><hr>
<h3>rest风格的url 添加书籍[post]h3>
<form action="?" method="?">
name:<input name="bookName" type="text"/><br/>
<input type="submit" value="添加书籍">
form>
<br/><hr>
<h3>rest风格的url 删除一本书h3>
<a href="?" id="?">删除指定id的书a>
<br/><hr>
<h3>rest风格的url 修改书籍[put]h3>
<form action="?">
<input type="submit" value="修改书籍">
form>
body>
html>
4.在com.zzw.web.rest
下, 创建BookHandler.java
1.完成查询
//BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {
//查询[GET]
@GetMapping(value = "/book/{id}")
public String getBook(@PathVariable("id") String id) {
System.out.println("查询书籍 id=" + id);
return "success";
}
}
5.前端修改请求地址
<h3>rest风格的url 查询书籍[get]h3>
<a href="user/book/200">点击查询书籍a>
2.完成添加
@PostMapping(value = "/book") @GetMapping(value = "/book/{id}")不重复
//BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {
//查询[GET]
@GetMapping(value = "/book/{id}")
public String getBook(@PathVariable("id") String id) {
System.out.println("查询书籍 id=" + id);
return "success";
}
//添加[POST]
@PostMapping(value = "/book")
public String addBook(String bookName) {
System.out.println("添加书籍 bookName=" + bookName);
return "success";
}
}
前端修改请求地址
<h3>rest风格的url 添加书籍[post]h3>
<form action="user/book" method="post">
name:<input name="bookName" type="text"/><br/>
<input type="submit" value="添加书籍">
form>
3.完成删除
//BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {
//查询[GET]
@GetMapping(value = "/book/{id}")
public String getBook(@PathVariable("id") String id) {
System.out.println("查询书籍 id=" + id);
return "success";
}
//添加[POST]
@PostMapping(value = "/book")
public String addBook(String bookName) {
System.out.println("添加书籍 bookName=" + bookName);
return "success";
}
//删除[DELETE]
@RequestMapping(value = "/book/{id}", method = RequestMethod.DELETE)
public String deleteBook(@PathVariable("id") String id) {
System.out.println("删除书籍 id=" + id);
//return "success";//[如果这样写会报错 JSP 只允许 GET、POST 或 HEAD]
//解读
//1. redirect:/user/success重定向
//2. 会被解析成 /工程路径/user/success
return "redirect:/user/success";//提示: 重定向不能重定向到WEB-INF下的资源, 所以需要借助successGeneral方法
}
//如果请求时 /user/success, 就转发到 success.jsp
//successGeneral 对应的url http://localhost:8080/springmvc/user/success
@RequestMapping(value = "/success")
public String successGeneral() {
return "success";//由该方法 转发到success.jsp页面
}
}
知识点:
1.web路径/script
目录下存放jquery文件, jquery复习
2.为什么前端做了一个操作后, 就可以被过滤器过滤处理, 定位到后端delete方法? 回答: HiddenHttpMethodFilter机制
3.return “success”; 会报以下错误
前端修改
<head>
<title>rest测试title>
<%--script标签建议放在head内--引入jquery--%>
<script type="text/javascript" src="script/jquery-3.6.0.min.js">script>
<script type="text/javascript">
$(function () {//当页面加载完成后就执行
// alert("ok...");
//给删除超链接绑定一个点击事件
$("#deleteBook").click(function () {
// alert("点击....");
//我们自己定义一个提交的行为
$("#hiddenForm").attr("action", this.href);
$("input:hidden").val("DELETE");
$("#hiddenForm").submit();
return false;//改变点击超链接的行为, 不再提交
})
});
script>
head>
<body>
<h3>rest风格的url 删除一本书h3>
<%--解读
1. 默认情况下, <a href="user/book/600">删除指定id的书a> 是get请求
2. 怎么样将 get 请求转成 springmvc 可以识别的 delete 请求, 就要考虑HiddenHttpMethodFilter
public static final String DEFAULT_METHOD_PARAM = "_method";
-------------------------------------------------------------------------------------------------------------
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
String paramValue = request.getParameter(this.methodParam);
if (StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
if (ALLOWED_METHODS.contains(method)) {
requestToUse = new HttpMethodRequestWrapper(request, method);
}
}
}
-------------------------------------------------------------------------------------------------------------
private static final List<String> ALLOWED_METHODS =
Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),
HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
3. 从上面代码可以看到 HiddenHttpMethodFilter 过滤器可以对以Post方式提交的delete, put, patch进行转换
, 转换称springmvc可以识别的 RequestMethod.DELETE / RequestMethod.PUT...
4. 我们需要将 get <a href="user/book/600">删除指定id的书a> 以 post方式提交给后端handler, 这样过滤器才会生效
5. 我们可以通过jquery来处理--引入jquery
--%>
<a href="user/book/600" id="deleteBook">删除指定id的书a>
<form action="" method="post" id="hiddenForm">
<input type="hidden" name="_method"/>
form>
body>
4.完成修改
//BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {
//修改[PUT]
@PutMapping(value = "/book/{id}")
public String updateBook(@PathVariable("id") String id) {
System.out.println("修改书籍 id=" + id);
return "redirect:/user/success";
}
}
前端修改请求代码
<h3>rest风格的url 修改书籍[put]h3>
<form action="user/book/666" method="post">
<input type="button" name="_method" value="PUT"/>
<input type="submit" value="修改书籍"/>
form>
1.HiddenHttpMethodFilter
, 在将post
转成delete / put
请求时, 是按_method
参数名 来读取的
2.如果web
项目是运行在Tomcat8
及以上, 会发现被过滤成DELETE
和PUT
请求, 到达控制器时能顺利执行, 但是返回时(forward)会报HTTP 405
的错误提示: JSP 只允许 GET、POST 或 HEAD
Tomcat7
forward
)改为请求重定向(redirect
): 重定向到一个Handler
, 由Handler
转发到页面3.页面测试时, 如果出现点击修改书籍, 仍然走的是删除url
, 是因为浏览器原因(缓存等原因).
需求说明
小王去商超买衣服, 完成购买衣服的增删改查
1.在web路径
下创建restBuyClothes.jsp
, 注意引入jquery
, 测试查询/添加/删除/修改
<head>
<title>购买衣服title>
<%--引入jquery--%>
<script type="text/javascript" src="script/jquery-3.6.0.min.js">script>
head>
<body>
<h3>rest风格的url 挑选衣服[get]h3>
<a href="?">点击挑选衣服a>
<br/><hr>
<h3>rest风格的url 添加衣服[post]h3>
<a href="?">点击添加衣服a>
<form action="?" method="post">
clothes: <input name="clothes" type="text"><br/>
<input type="submit" value="添加衣服">
form>
<br/><hr>
<h3>rest风格的url 删除一件衣服[delete]h3>
<a href="?" id="deleteClothes">删除一件衣服a>
<form action="" method="post" id="deleteForm">
<input type="hidden" name="_method"/>
form>
<br/><hr>
<h3>rest风格的url 修改衣服[get]h3>
<form action="?" method="post">
<input type="hidden" name="_method">
form>
body>
2.在com.zzw.web.rest
下, 创建ClothesHandler.java
1.完成查询
@PostMapping(value = "/clothes") @GetMapping(value = "/clothes/{brand}")不重复
@RequestMapping(value = "/user")//处理Rest风格的请求 增删改查
@Controller
public class ClothesHandler {
//挑选[GET]
@GetMapping(value = "/clothes/{brand}")
public String queryClothes(@PathVariable("brand") String brand) {
System.out.println("挑选衣服 brand=" + brand);
return "success";
}
}
.前端修改请求
<h3>rest风格的url 挑选衣服[get]h3>
<a href="user/clothes/阿迪达斯">点击挑选衣服a>
2.完成添加
@RequestMapping(value = "/user")
@Controller
public class ClothesHandler {//演示Rest风格的请求
//挑选[GET]
@GetMapping(value = "/clothes/{brand}")
public String queryClothes(@PathVariable("brand") String brand) {
System.out.println("挑选衣服 brand=" + brand);
return "success";
}
//添加[POST]
@PostMapping(value = "/clothes")
public String addClothes(String brand) {
System.out.println("添加衣服 brand=" + brand);
return "success";
}
}
.前端修改请求
<h3>rest风格的url 添加衣服[post]h3>
<form action="user/clothes" method="post">
clothes: <input name="brand" type="text"><br/>
<input type="submit" value="添加衣服">
form>
3.完成删除
@RequestMapping(value = "/user")
@Controller
public class ClothesHandler {//演示Rest风格的请求
//挑选[GET]
@GetMapping(value = "/clothes/{brand}")
public String queryClothes(@PathVariable("brand") String brand) {
System.out.println("挑选衣服 brand=" + brand);
return "success";
}
//添加[POST]
@PostMapping(value = "/clothes")
public String addClothes(String brand) {
System.out.println("添加衣服 brand=" + brand);
//return "success";
return "redirect:/user/success";
}
@RequestMapping(value = "/success2")
public String successGeneral() {
return "success";
}
}
.前端修改请求
<head>
<title>购买衣服title>
<%--引入jquery--%>
<script type="text/javascript" src="script/jquery-3.6.0.min.js">script>
<script type="text/javascript">
$(function () {
// alert("123");
$("#deleteClothes").click(function () {
// alert("ok..");
$("#deleteForm")[0].action = this.href;
$("input:hidden")[0].value = "DELETE";
$("#deleteForm").submit();
return false;
})
})
script>
head>
<body>
<h3>rest风格的url 删除一件衣服[delete]h3>
<a href="user/clothes/361" id="deleteClothes">删除一件衣服a>
<form action="" method="post" id="deleteForm">
<input type="hidden" name="_method"/>
form>
body>
4.完成修改
@RequestMapping(value = "/user")
@Controller
public class ClothesHandler {//演示Rest风格的请求
//挑选[GET]
@GetMapping(value = "/clothes/{brand}")
public String queryClothes(@PathVariable("brand") String brand) {
System.out.println("挑选衣服 brand=" + brand);
return "success";
}
//添加[POST]
@PostMapping(value = "/clothes")
public String addClothes(String brand) {
System.out.println("添加衣服 brand=" + brand);
//return "success";
return "redirect:/user/success";
}
@RequestMapping(value = "/success2")
public String successGeneral() {
return "success";
}
//修改[PUT]
@PutMapping(value = "/clothes/{brand}")
public String updateClothes(@PathVariable("brand") String brand) {
System.out.println("修改衣服 brand=" + brand);
return "redirect:/user/success2";
}
}
.前端修改请求
<body>
<h3>rest风格的url 修改衣服[get]h3>
<form action="user/clothes/李宁" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="修改衣服"/>
form>
body>
开发中, 如何获取到http://ip:port/url?
参数名=参数值&
参数名=参数值
1.com.zzw.web.requestParam
新建VoteHandler
@RequestMapping("/vote")
@Controller
public class VoteHandler {
/**
* 解读
* 1.获取到超链接传递的数据 请求 http://localhost:8080/springmvc/vote/vote01?name=xx
* 2.@RequestParam 表示会接收提交的参数
* 3,value="name" 表示提交的参数名是name
* 4.required=false 表示该参数可以没有; 默认是true, 表示必须有这个参数
* 5.当我们使用了 @RequestParam(value="name", required=false)后 请求的参数名和方法的形参名可以不一致
*/
@RequestMapping(value = "/vote01")
public String test01(@RequestParam(value = "name", required = false) String username) {
System.out.println("得到username=" + username);
return "success";
}
}
2.web路径
下新建request_parameter.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>测试 request parametertitle>
head>
<body>
<h2>获取到超链接参数值h2>
<hr>
<a href="vote/vote01?name=zzw">获取超链接的参数a>
body>
html>
3.Postman测试
●说明
1.在开发中, 如何获取到http
请求的消息头信息
2.使用较少
案例
1.修改VoteHandler.java
, 增加方法 test02
@RequestMapping("/vote")
@Controller
public class VoteHandler {
/**
* 需求: 获取http请求头信息, 获取到Accept-Encoding 和 Host
* [涉及到知识点 http协议]
* @param a1
* @param a2
* @return
*/
@RequestMapping(value = "/vote02")
public String test02(@RequestHeader("Accept-Encoding") String a1, @RequestHeader("Host") String a2) {
System.out.println("Accept-Encoding=" + a1);
System.out.println("Host=" + a2);
//返回一个结果
return "success";
}
}
修改request_parameter.jsp
<h2>获取到消息头h2>
<a href="vote/vote02">获取到Http消息头信息a>
开发中, 如何获取到javabean
对象, 就是以前的entity/pojo
对象数据
案例
1.com.zzw.web.requestParam.entity
包下新建Pet
类
public class Pet {
private Integer id;
private String name;
//setter, getter, toString方法
}
同包下新建Master
类
public class Master {
private Integer id;
private String name;
private Pet pet;//对象的属性是另外一个对象[涉及到属性级联]
//setter, getter, toString方法
}
2.修改VoteHandler.java
, 增加方法 test03
public class VoteHandler {
/**
* 演示如何获取到提交数据->封装成java对象
* 说明
* 1.方法的形参用对应的类型来指定即可, SpringMVC会自动的进行封装
* 2.如果要自动地完成封装, 要求提交的数据, 参数名和对象的字段名保持一致
* 3.如果属性是对象, 这里仍然是通过 字段名.字段名 比如Master [pet]
* , 即提交的数据 参数名 是 pet.id pet.name, 这就是级联操作
* 4.如果提交的数据 的参数名和对象的字段名不匹配, 则对象的属性值就是null
* @return
*/
@RequestMapping(value = "/vote03")
public String test03(Master master) {
System.out.println("master=" + master);
//返回结果
return "success";
}
}
3.修改request_parameter.jsp
<%--解读
1.这是一个表单, 表单的数据对应Master对象
2.提交的数据参数名和对象的字段名一致即可
--%>
<h1>添加主人信息h1>
<form action="vote/vote03" method="post">
主人:<input type="text" name="id"/><br/>
主人:<input type="text" name="name"/><br/>
宠物名:<input type="text" name="pet.id"/><br/>
宠物名:<input type="text" name="pet.name"/><br/>
<input type="submit" value="添加主人和动物"/>
form>
3.Postman
测试
1.支持级联数据获取
2.表单的控件名称name
需要和javabean
对象名称呼应, 否则就是null
●说明
1.开发中, 我们可以需要使用到原生的servlet api
2.使用servlet api
, 需要引入tomcat/lib
下的servlet-api.jar
案例
1.修改VoteHandler.java
, 增加方法 test04
@RequestMapping("/vote")
@Controller
public class VoteHandler {
/**
* 使用servlet api, 来获取提交的数据
* @param request
* @param response
* @return
*/
@RequestMapping(value = "/vote04")
public String test04(HttpServletRequest request,
HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username=" + username);
System.out.println("password=" + password);
//返回结果
return "success";
}
}
2.修改request_parameter.jsp
<h1>演示 servlet api的使用h1>
<form action="vote/vote04" method="post">
用户名:<input type="text" name="username"/><br/>
密 码:<input type="password" name="password"/><br/>
<input type="submit" value="提交"/>
form>
3.Postman
测试
post方式
提交
注意事项和细节
1.除了HttpServletRequest, HttpServletResponse
其它对象还可以以这样的方式获取
2.HttpSession, java.security.Principal, InputStream, OutputStream, Reader, Writer
3.其中一些对象也可以通过 HttpServletRequest / HttpServletResponse
对象获取, 比如Session
对象, 既可以通过参数传入, 也可以通过request.getSession()
获取, 效果一样, 推荐使用参数形式传入, 更加简单明了
@RequestMapping("/vote")
@Controller
public class VoteHandler {
/**
* 使用servlet api, 来获取提交的数据
* @param request
* @param response
* @return
*/
@RequestMapping(value = "/vote04")
public String test04(HttpServletRequest request,
HttpServletResponse response,
HttpSession session2) {
//获取到session
//servlet的原生的方式
HttpSession session = request.getSession();
System.out.println("session=" + session);
//注意: 通过参数传入的 session2 和 通过request.getSession()得到的 session对象是同一个
System.out.println("session2=" + session2);
//返回结果
return "success";
}
}
●说明
1.开发中, 控制器/处理器中获取的数据如何放入request
域, 然后在前端(VUE/JSP/...)
中显示
方式1:
通过HttpServletRequest
放入request
域
方式2:
通过请求的方法参数Maprequest
域
方式3:
通过返回 ModelAndView
对象实现request
域数据
1.web路径
下新建model_data.jsp
<head>
<title>测试 模型数据title>
head>
<body>
<h1>添加主人信息h1>
<form action="?" method="?">
主人号:<input type="text" name="?"/><br/>
主人名:<input type="text" name="?"/><br/>
宠物号:<input type="text" name="?"/><br/>
宠物名:<input type="text" name="?"/><br/>
<input type="submit" value="添加主人和动物"/>
form>
body>
2.修改VoteHandler.java
, 增加方法 test05
@RequestMapping("/vote")
@Controller
public class VoteHandler {
/**
* 1.演示将提交的数据->springmvc 封装到java对象->springmvc 会自动的将其放入到request域 [springmvc底层机制]
* 2.这样我们就可以在跳转到的页面取出数据.
* @return 参数名和对象的字段名保持一致
*/
@RequestMapping(value = "/vote05")
public String test05(Master master) {
//解读
//1.springmvc会自动地把获取的model模型, 放入到request域中, 名字就是master
// 在request域中: ("master", master对象)
//2.也可以手动将master放入到request...
//返回一个结果
return "vote_ok";
}
}
3.web路径/WEB-INF/pages目录
新建vote_ok.jsp
el表达式
<body>
<h1>获取到的数据显示页面h1>
<hr>
取出 request域的数据-通过el表达式获取即可
<br/>
address: <br/>
主人名字= ${requestScope.master.name}
主人id= ${requestScope.master.id}
宠物名字= ${requestScope.master.pet.name}
body>
4.完善model_data.jsp
<h1>添加主人信息h1>
<form action="vote/vote05" method="post">
主人号:<input type="text" name="id"/><br/>
主人名:<input type="text" name="name"/><br/>
宠物号:<input type="text" name="pet.id"/><br/>
宠物名:<input type="text" name="pet.name"/><br/>
<input type="submit" value="添加主人和动物"/>
form>
1.修改VoteHandler.java
, 增加代码
@RequestMapping("/vote")
@Controller
public class VoteHandler {
/**
* 1.演示将提交的数据->springmvc 封装到java对象->springmvc 会自动的将其放入到request域 [springmvc底层机制]
* 2.这样我们就可以在跳转到的页面取出数据.
* @return 参数名和对象的字段名保持一致
*/
@RequestMapping(value = "/vote05")
public String test05(Master master, HttpServletRequest request) {
//解读
//1.springmvc会自动地把获取的model模型, 放入到request域中, 名字就是master
// 在request域中: ("master", master对象)
//2.也可以手动将master放入到request
request.setAttribute("address", "济南");
//3.如果我们希望修改master的属性值
master.setName("coco");
//4.分析一下springmvc默认存放对象到request域中, 属性名是如何确定的
// request域 ("master", master) 属性名是类名/类型名 首字母小写
//返回一个结果
return "vote_ok";
}
}
2.vote_ok.jsp
<body>
<h1>获取到的数据显示页面h1>
<hr>
取出 request域的数据-通过el表达式获取即可
<br/>
address: <br/>
主人名字= ${requestScope.master.name}
主人id= ${requestScope.master.id}
宠物名字= ${requestScope.master.pet.name}
body>
1.修改model_data.jsp
, 增加代码
<h1>添加主人信息[测试 Map ]h1>
<form action="vote/vote06" method="post">
主人号:<input type="text" name="id"/><br/>
主人名:<input type="text" name="name"/><br/>
宠物号:<input type="text" name="pet.id"/><br/>
宠物名:<input type="text" name="pet.name"/><br/>
<input type="submit" value="添加主人和动物"/>
form>
2.修改VoteHandler.java
, 增加方法test06
@RequestMapping("/vote")
@Controller
public class VoteHandler {
/**
* 演示通过Map 设置数据到request域
* @return
*/
@RequestMapping(value = "/vote06")
public String test06(Master master, Map<String, Object> map) {
//解读
//1.需求是通过map对象, 添加属性到request中
//2.原理分析: springmvc会遍历map, 然后将map的k-v存放到request域中
map.put("address", "beijing...");
map.put("master", null);
//返回一个结果
return "vote_ok";
}
}
3.Postman
测试
1.修改model_data.jsp
, 增加代码
<h1>添加主人信息[测试ModelAndView]h1>
<form action="?" method="?">
主人号:<input type="text" name="id"/><br/>
主人名:<input type="text" name="name"/><br/>
宠物号:<input type="text" name="pet.id"/><br/>
宠物名:<input type="text" name="pet.name"/><br/>
<input type="submit" value="添加主人和动物"/>
form>
2.修改VoteHandler.java
, 增加方法test07
@RequestMapping("/vote")
@Controller
public class VoteHandler {
/**
* 演示通过返回ModelAndView对象, 将数据放入request中
* @return
*/
@RequestMapping(value = "/vote07")
public ModelAndView test07(Master master) {
ModelAndView modelAndView = new ModelAndView();
//放入属性到modelAndView对象
modelAndView.addObject("address", "shanghai~");
modelAndView.addObject("master", null);
//可以把从数据库得到的数据->对象->放入到modelAndView[service-dao-db]
//这里指定要跳转的视图名称
modelAndView.setViewName("vote_ok");
//返回结果
return modelAndView;
}
}
3.完善model_data.jsp
<h1>添加主人信息[测试ModelAndView]h1>
<form action="vote/vote07" method="post">
主人号:<input type="text" name="id"/><br/>
主人名:<input type="text" name="name"/><br/>
宠物号:<input type="text" name="pet.id"/><br/>
宠物名:<input type="text" name="pet.name"/><br/>
<input type="submit" value="添加主人和动物"/>
form>
4.Postman
测试
post方式
提交
注意事项和细节
1.从本质看, 请求响应的方法return xx
时返回了一个字符串, 其实本质是返回了一个ModeAndView
对象, 只是默认被封装起来的.
2.ModelAndView
即可以包含model
数据, 也可以包含视图信息
3.ModelAndView
对象的addObject
方法可以添加key-val
数据.
4.ModelAndView
对象setView
方法可以指定视图名称
说明
开发中, 控制器 / 处理器中获取的数据如何放入session
域, 然后在前端(VUE/JSP/...)
取出显示.
案例
1.修改model_data.jsp
, 增加代码
<h1>添加主人信息[测试session]h1>
<form action="?" method="?">
主人号:<input type="text" name="id"/><br/>
主人名:<input type="text" name="name"/><br/>
宠物号:<input type="text" name="pet.id"/><br/>
宠物名:<input type="text" name="pet.name"/><br/>
<input type="submit" value="添加主人和动物"/>
form>
2.修改VoteHandler.java
, 增加方法test08
@RequestMapping("/vote")
@Controller
public class VoteHandler {
/**
* 演示如何将数据设置到session域中
* @return
*/
@RequestMapping(value = "/vote08")
public String test08(Master master, HttpSession httpSession) {
//master对象是默认放在request域中
//我们将master对象放入到session
httpSession.setAttribute("master", master);
httpSession.setAttribute("address", "beijing``");
return "vote_ok";
}
}
3.vote_ok.jsp
增加代码
<head>
<title>vote_oktitle>
head>
<body>
取出 session域的数据<br/>
address: ${sessionScope.address}<br/>
主人名字= ${sessionScope.master.name}<br/>
主人信息= ${sessionScope.master}<br/>
body>
4.完善model_data.jsp
<h1>添加主人信息[测试session]h1>
<form action="vote/vote08" method="post">
主人号:<input type="text" name="id"/><br/>
主人名:<input type="text" name="name"/><br/>
宠物号:<input type="text" name="pet.id"/><br/>
宠物名:<input type="text" name="pet.name"/><br/>
<input type="submit" value="添加主人和动物"/>
form>
4.Postman
测试
●基本说明
开发中, 有时需要使用某个前置方法(比如prepareXxx()
, 方法名由程序员定)给目标方法准备一个模型对象
1.@ModelAttribute
注解可以实现 这样的需求
2.在某个方法上, 增加了@ModelAttribute
注解后
3.那么在调用该Handler
的任何一个方法时, 都会先调用这个方法
案例
1.修改VoteHandler.java
, 增加方法prepareModel
/**
* 解读
* 1.当Handler的方法被标识 @ModelAttribute, 就视为一个前置方法
* 2.当调用Handler的其它方法时, 都会先执行该前置方法
* 3.类似我们前面学习Spring时, AOP的前置通知
* 4.prepareModel 前置方法, 会切入到其它方法前执行. 底层是AOP机制
*/
@ModelAttribute
public void prepareModel() {
System.out.println("prepareModel.........完成准备工作.........");
}
@ModelAttribute最佳实践
修改用户信息(就是经典的使用这种机制的应用), 流程如下
1.在修改前, 在前置方法中从数据库查出这个用户
2.在修改方法(目标方法)中, 可以使用前置方法从数据库查询这个对象
3.如果表单中对用户的某个属性修改了, 则以新的数据为准, 如果没有修改, 则以数据库的信息为准. 比如, 用户的某个属性不能修改, 就保持原来的值.
基本介绍
1.在SpirngMVC
中的目标方法最终返回都是一个视图(有各种视图)
2.返回的视图都会由一个视图解析器来处理(视图解析器有很多种)
1.在默认情况下, 我们都是返回默认的视图, 然后返回的视图交由SpringMVC
的InternalResourceViewResolver
视图解析器来处理的.
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
bean>
2.在实际开发中, 我们有时需要自定义视图, 这样可以满足更多更复杂的需求.
实例-代码实现
1.在web路径
目录下 新建view.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>自定义视图测试title>
head>
<body>
<h2>自定义视图测试h2>
<a href="?">点击到自定义视图a>
body>
html>
2.com.zzw.web.viewresolver
包下 新建GoodsHandler
@RequestMapping("/goods")
@Controller
public class GoodsHandler {
@RequestMapping("/buy")
public String buy() {
System.out.println("buy() 被调用...");
return "?";//待会再填写自定义视图名称
}
}
3.com.zzw.web.viewresolver
包下 新建MyView
/**
* 解读
* 1.MyView 继承了AbstractView, 就可以作为一个视图使用
* 2.@Component(value="myView"), 该视图会注入到容器中, 名字/id 是 zzwView
*/
@Component(value = "zzwView")
public class MyView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
//完成视图渲染
//并且可以确定我们要跳转的页面
System.out.println("进入到自己的视图");
}
}
4.在web路径/WEB-INF/pages目录
下 新建my_view.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>my_view页面title>
head>
<body>
<h2>进入到my_view页面h2>
<p>是从自定义视图来的p>
body>
html>
5.补充MyView
的代码
/**
* 解读
* 1.MyView 继承了AbstractView, 就可以作为一个视图使用
* 2.@Component(value="myView"), 该视图会注入到容器中, 名字/id 是 zzwView
*/
@Component(value = "zzwView")
public class MyView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
//完成视图渲染
//并且可以确定我们要跳转的页面[请求转发] /WEB-INF/pages/my_view.jsp
System.out.println("进入到自己的视图");
//解读
//1.下面就是进行请求转发到 /WEB-INF/pages/my_view.jsp
//2./WEB-INF/pages/my_view.jsp 会被springmvc解析
// /springmvc/WEB-INF/pages/my_view.jsp
request.getRequestDispatcher("/WEB-INF/pages/my_view.jsp")
.forward(request, response);
}
}
6.配置springDispatcherServlet-servlet.xml
, 增加自定义视图解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
bean>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="99"/>
bean>
7.view.jsp
修改请求路径
<h2>自定义视图测试h2>
<a href="goods/buy">点击到自定义视图a>
8.GoodsHandler.java
完善代码
@RequestMapping("/goods")
@Controller
public class GoodsHandler {
@RequestMapping("/buy")
public String buy() {
System.out.println("buy() 被调用...");
return "zzwView";//待会再填写自定义视图名称
}
}
1.创建一个View
的bean
, 该bean
需要继承自AbstractView
, 并实现renderMergedOutputModel
方法
2.并把自定义View
加入到IOC
容器中
3.自定义视图的视图处理器, 使用BeanNameViewResolver
, 这个视图处理器也需要配置到ioc
容器
4.BeanNameViewResolver
的调用优先级需要设置一下, 设置order
比Integer.MAX_VALUE
小的值, 以确保其在InternalResourceViewResolver
之前被调用
1.SpringMVC
调用目标方法, 返回自定义View
在IOC
容器中的id
2.SpringMVC
调用BeanNameViewResolver
解析视图: 从IOC
容器中获取 返回id
值对应的bean
, 即自定义View
的对象
3,SpringMVC
调用自定义视图的renderMergedOutputModel
方法渲染视图
4.说明:
如果在SpringMVC
调用目标方法, 返回自定义View
容器中的id
, 不存在, 则仍然按照默认的视图处理器机制处理.
debug源码
判断是否实现了View接口, 如果实现了, 返回View对象
进入到my_view.jsp
1.配置默认视图解析器的优先级
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="10"/>
bean>
2.debug源码
进入到默认视图解析器
由于没有zzwView.jsp页面, 页面会报错
案例1: 假设自定义视图解析器的优先级大于默认视图解析器
1.将默认视图解析器的优先级大小设置为默认
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
bean>
2.将自定义视图MyView.java的beanName改为zzwViewx
/**
* 解读
* 1.MyView 继承了AbstractView, 就可以作为一个视图使用
* 2.@Component(value="myView"), 该视图会注入到容器中, 名字/id 是 zzwView
*/
@Component(value = "zzwViewx")
public class MyView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
//完成视图渲染
//并且可以确定我们要跳转的页面[请求转发] /WEB-INF/pages/my_view.jsp
System.out.println("进入到自己的视图");
//解读
//1.下面就是进行请求转发到 /WEB-INF/pages/my_view.jsp
//2./WEB-INF/pages/my_view.jsp 会被springmvc解析
// /springmvc/WEB-INF/pages/my_view.jsp
request.getRequestDispatcher("/WEB-INF/pages/my_view.jsp")
.forward(request, response);
}
}
3.debug源码
在容器中找不到id为zzwView
的bean对象. 参数viewName
是zzwView
,
BeanName视图解析器返回了空, 开始循环第二个默认视图解析器
对返回的view对象进行估算. 没有 /WEB-INF/pages/zzwView.jsp 这个文件, 会报404错误.
案例2: 假设默认视图解析器的优先级大于自定义视图解析器
1.将默认视图解析器的优先级大小设置为10, 此时自定义视图解析器的优先级是99.
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="10"/>
bean>
2.将自定义视图MyView.java的beanName改为zzwView
/**
* 解读
* 1.MyView 继承了AbstractView, 就可以作为一个视图使用
* 2.@Component(value="myView"), 该视图会注入到容器中, 名字/id 是 zzwView
*/
@Component(value = "zzwView")
public class MyView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
//完成视图渲染
//并且可以确定我们要跳转的页面[请求转发] /WEB-INF/pages/my_view.jsp
System.out.println("进入到自己的视图");
//解读
//1.下面就是进行请求转发到 /WEB-INF/pages/my_view.jsp
//2./WEB-INF/pages/my_view.jsp 会被springmvc解析
// /springmvc/WEB-INF/pages/my_view.jsp
request.getRequestDispatcher("/WEB-INF/pages/my_view.jsp")
.forward(request, response);
}
}
3.debug源码
只要执行了默认视图解析器, 找不到页面, 会报404, 不会再执行下一个视图解析器.
● 目标方法中指定转发或者重定向
1.默认返回的方法是请求转发, 然后用视图处理器进行处理, 比如在目标方法中这样写:
2.也可以在目标方法中直接指定重定向或请求转发的url
地址
但是有个例外: 不能重定向到/WEB-INF
目录.
原因: WEB-INF下的资源是服务器内部访问的, 浏览器不能访问
案例
1.修改com.zzw.web.viewresolver.GoodsHandler.java
, 增加方法order
@RequestMapping("/goods")
@Controller
public class GoodsHandler {
@RequestMapping("/order")
public String order() {
System.out.println("===========order()===========");
//请求转发到 /WEB-INF/pages/my_view.jsp
//下面的这个路径 /WEB-INF/pages/my_view.jsp 会被解析成 /springmvc/WEB-INF/pages/my_view.jsp
//return "forward:/WEB-INF/pages/my_view.jsp";
//return "forward:/aa/bb/ok.jsp";
//直接指定要重定向的页面
//1. 对应重定向来说, 不能重定向到 /WEB-INF/ 目录下
//2. redirect 关键字, 表示进行重定向
//3. /login.jsp 在服务器解析成 /springmvc/login.jsp
return "redirect:/login.jsp";
//http://localhost:8080/springmvc/WEB-INF/pages/my_view.jsp
//浏览器不能访问WEB-INF下的资源
//return "redirect:/WEB-INF/pages/my_view.jsp";
}
}
2.view.jsp
增加代码
<body>
<h2>自定义视图测试h2>
<a href="goods/buy">点击到自定义视图a><br/>
<a href="goods/order">测试在目标方法中指定请求转发或者重定向到页面a>
body>
测试1
1.请求转发到 /WEB-INF/pages/my_view.jsp
2.下面的这个路径 /WEB-INF/pages/my_view.jsp 会被解析成 /springmvc/WEB-INF/pages/my_view.jsp
return "forward:/WEB-INF/pages/my_view.jsp";
测试2
1.请求转发到 /aa/bb/ok.jsp
2.下面的这个路径 /aa/bb/ok.jsp 会被解析成 /springmvc/aa/bb/ok.jsp
return "forward:/aa/bb/ok.jsp";
测试3
直接指定要重定向的页面
1.对应重定向来说, 不能重定向到 /WEB-INF/ 目录下
2.redirect 关键字, 表示进行重定向
3./login.jsp 在服务器解析成 /springmvc/login.jsp
return "redirect:/login.jsp";
测试4
1.重定向到 /WEB-INF/pages/my_view.jsp
2.下面的这个路径 /WEB-INF/pages/my_view.jsp 在服务器会被解析成 /springmvc/WEB-INF/pages/my_view.jsp
//http://localhost:8080/springmvc/WEB-INF/pages/my_view.jsp
return "redirect:/WEB-INF/pages/my_view.jsp";
debug源码
开始渲染
renderMergedOutputModel()
和MyView.java
中的相仿
rd = request.getRequestDispatcher(dispatcherPath);
debug源码
调用RedirectView
的视图渲染方法
1.熟悉前面的SpringMVC
映射数据请求, 模型数据, 视图和视图解析的案例
2.清晰Debug源码
的流程
3.完成一个简单的用户登录案例
1)编写登陆页面login.jsp
2)LoginHandler [doLogin方法]
, 如果用户输入用户名是zzw
, 密码123
, 就可以登陆成功; 否则登陆失败
3)创建JavaBean: User.java
4)表单提交数据到doLogin
方法, 以User
对象形式接收
5)登陆成功到, 页面 login_ok.jsp
, 并显示登陆欢迎信息 [显示用户名, 模型数据会自动填充到request域中]
6)登陆失败到, 页面 login_err.jsp
, 并给出重新登录的超链接 [考察web工程路径应用问题]
代码实现
1.在web路径/homework
下 新建login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登陆页面title>
head>
<body>
<form action="?">
用户名: <input name="username" type="text"/><br/>
密 码: <input name="password" type="password"/><br/>
<input type="submit" value="登录"/>
form>
body>
html>
2.在com.zzw.web.homework
下新建LoginHandler
@Controller
@RequestMapping(value = "/user")
public class LoginHandler {
//处理登录
@RequestMapping(value = "/doLogin", params ={"username","password"}, method = RequestMethod.GET)
public String doLogin(String username, String password) {
System.out.println(username);//测试
System.out.println(password);//测试
if ("zzw".equals(username) && "123".equals(password)) {
System.out.println("登录成功");
} else {
System.out.println("登陆失败");
}
return "";
}
}
3.填充login.jsp
的请求路径 涉及-web工程路径问题
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登陆页面title>
head>
<body>
<form action="../user/doLogin">
用户名: <input name="username" type="text"/><br/>
密 码: <input name="password" type="password"/><br/>
<input type="submit" value="登录"/>
form>
body>
html>
也可以这么写
<%--
<%=request.getContextPath()%>/user/doLogin => /springmvc/user/doLogin
/springmvc/user/doLogin 被浏览器解析成 http://localhost:8080/springmvc/user/doLogin
--%>
<form action="<%=request.getContextPath()%>/user/doLogin">
4.在com.zzw.web.homework.entity
下新建User.java
public class User {
private String username;
private String password;
//setter, getter, toString方法
}
5.表单登录提交到doLogin
方法, 以User
对象形式接收 封装成javaBean. 修改UserHandler
@Controller
@RequestMapping(value = "/user")
public class LoginHandler {
@RequestMapping(value = "/doLogin", params ={"username","password"}, method = RequestMethod.GET)
public String doLogin(User user) {
System.out.println(user.getUsername());//测试
System.out.println(user.getPassword());//测试
if ("zzw".equals(user.getUsername()) && "123".equals(user.getPassword())) {
System.out.println("登录成功");
} else {
System.out.println("登陆失败");
}
return "";
}
}
6.登录成功到login_ok.jsp
, 并显示登陆欢迎信息 模型数据默认放入request域. 在web路径/WEB-INF/pages/homework
下 新建login_ok.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登陆成功title>
head>
<body>
<h1>欢迎 ${requestScope.user.username} 登陆成功h1>
body>
html>
7.登陆失败到login_err.jsp
, 并给出重新登陆的超链接. 在web路径/WEB-INF/pages/homework
下 新建login_err.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登陆失败</title>
</head>
<body>
<h1>登陆失败</h1>
<a href="?">重新登陆</a>
</body>
</html>
8.在springDispatcherServlet-servlet.xml
中增加一个优先级为9
解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver02">
<property name="prefix" value="/WEB-INF/pages/homework/"/>
<property name="suffix" value=".jsp"/>
<property name="order" value="9"/>
bean>
9.修改UserHandler
注释部分参考服务器对路径的解析
@Controller
@RequestMapping(value = "/user")
public class LoginHandler {
@RequestMapping(value = "/doLogin", params ={"username","password"}, method = RequestMethod.GET)
public String doLogin(User user) {
if ("zzw".equals(user.getUsername()) && "123".equals(user.getPassword())) {
//也可以这么写
//return "forward:/WEB-INF/pages/homework/login_ok.jsp";
return "login_ok";
} else {
//也可以这么写
//return "forward:/WEB-INF/pages/homework/login_err.jsp";
return "login_err";
}
}
}
11.完成重新登录的超链接
我们可以查看到当前浏览器地址栏的路径, 根据 相对路径的知识点, 我们完善login_err.jsp
重新登陆的超链接
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登陆失败title>
head>
<body>
<h1>登陆失败h1>
<a href="../homework/login.jsp">重新登陆a>
body>
html>
也可以这么写
<%--
<%=request.getContextPath()%>/homework/login.jsp
即 /springmvc/homework/login.jsp
会被浏览器解析成 http://localhost:8080/springmvc/homework/login.jsp
--%>
<a href="<%=request.getContextPath()%>/homework/login.jsp">重新登陆a>
下一篇: 手动实现SpringMVC底层机制, 敬请期待…