SSM整合尚硅谷SpringMVC
SpringMVC 1.SpringMVC概述 MVC:
Model(模型): 提供要显示的数据模型:Value Object(数据Dao) 和 服务层(行为Service),提供数据和业务。
View(视图): 负责模型的显示,即用户界面
Controller(控制器): 调度员,接收用户请求,委托模型处理(状态变化),处理后将返回的模型数据返回视图,视图显示。
SpringMVC的特点:
Spring为显示层提供基础MVC设计理念的Web框架
SpirngMVC通过一套MVC注解,让POJO在没有任何接口的情况下,成为处理请求的控制器
支持REST风格的URL请求
可拉插组件结构采用松散耦合,扩展灵活
-
HelloWorld
-
导入依赖 spring-webmvc的maven依赖
org.springframework spring-web 4.0.0.RELEASE<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.0.0.RELEASE</version> </dependency> <!-- 核心包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.0.0.RELEASE</version> </dependency> <!-- 日志包--> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </dependency> <!-- 注解支持包--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.0.0.RELEASE</version> </dependency>
-
配置web.xml , 注册DispatcherServlet DispatcherServlet:负责请求分发的前端控制器。
要绑定Spring的配置文件
<?xml version="1.0" encoding="UTF-8"?><!--注册DispatcherServlet,要求分发器(前端控制器)--> <servlet> <servlet-name>springDispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--绑定Spring配置文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-config.xml</param-value> </init-param> <!--启动级别为1,即服务器启动后启动--> <!--启动级别为1,即服务器启动后启动--> <!--值越小,优先级越高,对象越先创建--> <load-on-startup>1</load-on-startup> </servlet> <!-- / 拦截所有的请求;(不包括.jsp,jsp由Tomcat来处理), 覆盖父类DispatcherServlet的pattern,拦截静态资源。--> <!-- *.jsp 拦截jsp覆盖父类的请求JspServlet--> <!-- /* 拦截所有请求;(包括.jsp,一旦拦截jsp页面无法显示)--> <servlet-mapping> <servlet-name>springDispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
3. 导入Spring配置文件 Spring的配置文件Springmvc-config.xml。
打开包扫描,使指定包下的注释生效IOC统一管理容器
视图视图分析器InternalResourceViewResolver,这里可以设置前缀和后缀,拼接视图名称
<?xml version="1.0" encoding="UTF-8"?><!--打开包扫描,使指定包下的注释生效IOC统一管理容器--> <context:component-scan base-package="com.xiao.controller"/> <!--配置视图分析器,拼接视图名称,找到相应的视图--> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/page/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean>
4. 编写controller层 HelloController类:
@Controller:告诉Spirng这是一个控制器IOC容器管理
@RequestMapping("/hello01"):/ 表示项目地址,请求项目时hello01点,返回一个/WEB-INF/page/success.jsp页面给前端
@Controller public class HelloController {
@RequestMapping("/hello01") public String toSuccess(){ System.out.println("请求页面成功"); return "success"; } @RequestMapping("/hello02") public String toError() { System.out.println("请求错误页面"); return "error"; }
} 5. 编写跳转的jsp页面 项目首页 index.jsp,两个超链接分别发出hello01和hello02的请求
<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>
点击这里成功页面 点击失败页面p 成功页面success.jsp和失败页面error.jsp,要注意文件的路径/WEB-INF/page/…jsp,与上面的保持一致
<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>
这里是成功页面
<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>
这里是错误页面
6) 访问启动项目:
点击去成功页面,可以看到发出了/hello01请求,页面转发到/WEB-INF/page/success.jsp,控制台输出了请求成功页面。
- Url请求 3.1 运行流程 客户端点击链接发送请求:http://localhost:8080/hello01;
来到tomcat服务器;
SpringMVC的前端控制器收到所有请求;
看请求地址和@RequestMapping标注的哪个匹配,来找到底使用哪个类的哪个方法来处理;
前端控制器找到目标处理器类和目标方法,直接利用反射执行目标方法;
方法执行完后有一个返回值,SpringMVC认为这个返回值就是要去的页面地址;
拿到方法返回值后,视图解析器进行拼串得到完整的页面地址
得到页面地址,前端控制器帮我们转发到页面
3.2 url映射 RequestMapping
01 标注在方法上
告诉SpringMVC这个方法用来处理什么请求。
@RequestMapping("/hello01")中的 /可以省略,就是默认从当前项目下开始。
02 标注在类上
表示为当前类中的所有方法的请求地址,指定一个基准路径(都是从这里开始的)的,不是指定拼串前缀的。所以toSuccess()方法的RequestMapping 中hello01前不加/,写成@RequestMapping(value = “hello01”),也可以访问,其访问路径也是路径是haha/hello01。
@Controller @RequestMapping("/haha") public class HelloController {
@RequestMapping(value = “/hello01”) public String toSuccess(){
System.out.println(“请求成功页面”); return “success”; } } 注意前端路径不加/
03 规定请求方式
method属性规定请求方式,默认是所求请求方式都行。method = RequestMethod.GET,method = RequestMethod.POST。
如果方法不匹配会报:HTTP Status 405 错误 – 方法不被允许 1)、 @RequestMapping(value = “/hello01”,method = RequestMethod.GET) public String toSuccess(){ System.out.println(“请求成功页面”); return “success”; }
2)、
组合用法
@GetMapping 等价于 @RequestMapping(method =RequestMethod.GET)
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
04 规定请求参数
params属性规定请求参数,是一个数组。 会造成错误:HTTP Status 400 – 错误的请求
不携带该参数,表示参数值为null;携带了不给值表示参数值是空串
//必须携带username参数
@RequestMapping(value = “/hello03”,params ={“username”}) //必须不携带username参数 @RequestMapping(value = “/hello03”,params ={"!username"}) //必须携带username参数,且值必须为123 @RequestMapping(value = “/hello03”,params ={“username=123”}) //username参数值必须不为123,不携带或者携带了不是123都行 不携带:即null 带空串:携带了不给值 不是123:
@RequestMapping(value = “/hello03”,params ={“username=!123”}) //username参数值必须不为123,不携带password,携带page
@RequestMapping(value = “/hello03”,params ={“username=!123”,“page”,"!password"}) 05 规定请求头
headers属性规定请求头。其中User-Agent:浏览器信息
谷歌浏览器:User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.3
06 Ant风格URL
URL地址可以写模糊的通配符,模糊和精确多个匹配情况下精确优先。 例如: @RequestMapping( “/hello01”) 和 @RequestMapping( “/hello0?”) / 访问hello01的话执行的是@RequestMapping( “/hello01”)
?:替代任意一个字符
@RequestMapping( “/hello0?”) /
*:替代任意多个字符或一层路径
@RequestMapping( “/hello0*”) //任意多个字符 @RequestMapping( “/a/*/hello01”) //一层路径 @RequestMapping(value = “/test/*/a”) public String myMethodTest01() { System.out.println(“post01”); return “success”; } // test/[^/]+/b ->post01 // /test/*/b ->post02 @RequestMapping(value = “/test/**/a”) public String myMethodTest02() { System.out.println(“post02”); return “success”; } **:替代任意多层路径
@RequestMapping( “/a/**/hello01”) //任意多层路径 @RequestMapping( “/a/**/hello01”) 和@RequestMapping( “/a/*hello01”) 同时出现,优先访问精确路径(一个*的):@RequestMapping( “/a/*/hello01”)
07 PathVariable
可以用/test/{paramsName1}/{paramsName2}来获取Url上传的参数值
//获取到{id}占位符,占位符可以在任意路径地方写{变量名}
//@PathVariable("id") 获取请求路径哪个占位符的值
@RequestMapping(value = "/test/{id}", method = RequestMethod.GET)
public String myMethodTest03(@PathVariable("id") String id) {
System.out.println("路径上占位符"+id);
return "success";
}
3.3 Spring配置文件的默认位置 默认位置是 /WEB-INF/xxx-servlet.xml,其中xxx是自己在web.xml文件中配置的servlet-name属性。
例如:
dispatcherServlet-servlet.xml
当然也可以手动指定文件位置。
dispatcherServlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:applicationContext.xml 13.5 url-pattern / 拦截所有的请求,不拦截jsp
/* 拦截所有的请求,包括*.jsp,一旦拦截jsp页面就不能显示了。. jsp是tomcat处理的事情
看Tomcat的配置文件web.xml中,有DefaultServlet和JspServlet,
DefaultServlet是Tomcat中处理静态资源的,Tomcat会在服务器下找到这个资源并返回。如果我们自己配置url-pattern=/,相当于禁用了Tomcat服务器中的DefaultServlet,这样如果请求静态资源,就会去找前端控制器找@RequestMapping,这样静态资源就不能访问了。解决办法:
<mvc:default-servlet-handler />
mvc:annotation-driven/
- REST风格 4.1 概述 REST就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。其强调HTTP应当以资源为中心,并且规范了URI的风格;规范了HTTP请求动作(GET/PUT/POST/DELETE/HEAD/OPTIONS)的使用,具有对应的语义。
资源(Resource):网络上的一个实体,每种资源对应一个特定的URI,即URI为每个资源的独一无二的识别符;
表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层。比如txt、HTML、XML、JSON格式等;
状态转化(State Transfer):每发出一个请求,就代表一次客户端和服务器的一次交互过程。GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。
在参数上使用 @PathVariable 注解,可以获取到请求路径上的值,也可以写多个
@RequestMapping(value = "/hello04/username/{id}")
public String test2(@PathVariable("id") int id){
System.out.println(id);
return "success";
}
4.2 CRUD REST风格的URL地址 <a href=“book/1”>:book前不用加/,否则需要加项目名, 4.3页面上发出PUT请求 对一个资源的增删改查用请求方式来区分:
/book/1 GET:查询1号图书
/book/1 DELETE:删除1号图书
/book/1 PUT:修改1号图书
/book POST:新增图书
页面上只能发出GET请求和POST请求。将POST请求转化为put或者delete请求的步骤:
把前端发送方式改为post 。
在web.xml中配置一个filter:HiddenHttpMethodFilter过滤器
必须携带一个键值对,key=_method, value=put或者delete
HiddenHttpMethodFilter org.springframework.web.filter.HiddenHttpMethodFilter HiddenHttpMethodFilter /* 注意高版本Tomcat会出现问题:JSPs only permit GET POST or HEAD,在页面上加上异常处理即可
<%@ page contentType=“text/html;charset=UTF-8” language=“java” isErrorPage=“true” %>
案例: web.xml 配置hiddenHttpMethodFilter
<?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">
<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:applicationContext.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern> </filter-mapping> </web-app>
controller:
package com.kxy.springmvcparam;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class RestTest {
@RequestMapping(value = "/book/{bid}",method = RequestMethod.GET)
public String getBook(@PathVariable("bid")Integer id){
System.out.println("查询"+id+"号图书");
return "success";
}
@RequestMapping(value = "/book/{bid}",method = RequestMethod.DELETE)
public String deleteBook(@PathVariable("bid")Integer id){
System.out.println("删除"+id+"号图书");
return "success";
}
@RequestMapping(value = "/book/{bid}",method = RequestMethod.PUT)
public String updateBook(@PathVariable("bid")Integer id){
System.out.println("更新"+id+"号图书");
return "success";
}
@RequestMapping(value = "/book",method = RequestMethod.POST)
public String addBook(){
System.out.println("新增图书");
return "success";
}
}
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" **isErrorPage="true"** %>
<%
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
%>
<html>
<head>
<base href="<%=basePath%>">
<title>请求页面</title>
</head>
<body>
<br/>
<br/>
<a href="book/1">查询图书</a><br/>
<form action="book" method="post">
<input type="submit" value="新增图书">
</form>
<br/>
<form action="book/1" method="post">
<input type="hidden" name="_method" value="delete">
<input type="submit" value="删除图书">
</form>
<br/>
<form action="book/1" method="post">
<input type="hidden" name="_method" value="put">
<input type="submit" value="更新图书">
</form>
</body>
</html>
success.jsp 一定要添加 isErrorPage=“true”
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<%
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
%>
<html>
<head>
<base href="<%=basePath%>">
<title>返回页面1</title>
</head>
<body>
返回成功
</body>
</html>
5 请求参数处理 5.1 传入参数
- 如果提交的参数名称和处理方法的参数名一致,则无需处理,直接使用 index.jsp
controller
没使用@RequestParam之前
默认方式获取请求参数: 直接给方法入参上写一个和请求参数名相同的变量。这个变量就来接收请求参数的值 请求带参数:有值,没带:null
- 提交的参数名称和处理方法的参数名不一致,使用@RequestParam注解
@RequestParam:获取请求参数的,参数默认是必须带的,不然会报错
四个参数:
value: 指定要获取的参数key required: 这个参数是否必须要传一个值 defaultValue: 默认值。没带默认是null name等同于value
@RequestMapping(value = "/hello03",params ={
"username"})
public String test03(@RequestParam("user")String username)
//***等价于 username = request.getParameter("user"))***
//传入网址为:"handle01?user=aaa"
@RequestMapping("/hello05")
public String test03(@RequestParam(value = "username",required = false, defaultValue ="hehe" ) String name) {
System.out.println(name);
return "success";
}
//比较 /book/{user01}?user02=admin @ReqquestParam(“user02”) 获取问号后面请求参数user02的值 @PathVariable(“user01”) 获取路径中user01的值
还有另外两个注解:
@RequestHeader:获取请求头中某个key的值; 比如User-Agent:浏览器信息 @RequestHeader(“User-Agent”)String userAgent 等同于:request.getHeader(“User-Agent”) 如果请求头中没有这个值就会报错; @RequestHeader注解的三个参数: value:指定要获取的参数的key ,此参数可以不带,也可以指定默认值 required:boolen类型,指这个参数是否必须的,默认为true,即请求中必须带此参数,false:请求中可以不带此参数, defaultValue:默认值。没带参数默认是null,也可以自己指定值;
@RequestMapping("/hello05")
public String test03(@RequestHeader("User-Agent" ) String name) {
System.out.println(name);
return "success";
}
@CookieValue:获取某个cookie的值
@RequestMapping("/hello05") public String test03(@CookieValue(“JSESSIONID” ) String name) { System.out.println(name); return “success”; } 等价于 Cookie[] cookies = request.getCookies(); for(Cookie c:cookies){ if(c.getName().equals(“JSESSIONID”)){ String cookievalue = c.getValue(); } } @CookieValue注解的三个参数 value:指定要获取的参数的key ,此参数可以不带,也可以指定默认值 required:boolen类型,指这个参数是否必须的,默认为true,即请求中必须带此参数,false:请求中可以不带此参数, defaultValue:默认值。没带参数默认是null,也可以自己指定值;
5.2 传入一个对象 传入POJO,SpringMVC会自动封装,提交的表单域参数必须和对象的属性名一致,否则就是null,请求没有携带的字段,值也会是null。同时也还可以级联封装。
新建两个对象User和Address:
public class User {
private String username;
private Integer age;
private Address address;
//getter()、setter()、toString()....
}
public class Address {
private String name;
private Integer num;
//getter()、setter()、toString()....
}
前端请求:
<form action="hello06" method="post">
姓名: <input type="text" name="username"> <br>
年龄: <input type="text" name="age"><br>
地址名:<input type="text" name="address.name"><br>
地址编号:<input type="text" name="address.num"><br>
<input type="submit" name="提交">
</form>
后端通过对象名也能拿到对象的值,没有对应的值则为null
@RequestMapping("/hello06")
public String test03(User user) {
System.out.println(user);
return "success";
}
测试:
5.3 传入原生ServletAPI 以上给session中保存一些东西,会不好实现,可以通过原生API:
处理方法还可以传入原生的ServletAPI: 向session域中保存数据
@RequestMapping("/hello07")
public String test04(HttpServletRequest request, HttpSession session) {
session.setAttribute("sessionParam","我是session域中的值");
request.setAttribute("reqParam","我是request域中的值");
return "success";
}
通过EL表达式获取到值,${requestScope.reqParam}:
<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<head>
<title>成功页面</title>
</head>
<body>
<h1>这里是成功页面</h1>
请求:${
requestScope.reqParam}
session:${
sessionScope.sessionParam}
</body>
</html>
可以传的参数类型9种:可以使用的只有前三个 * HttpServletRequest * HttpServletResponse * HttpSession * * * java.security.Principal https安全协议有关的, * Locale:国际化有关的区域信息对象 * InputStream:字节流 * ServletInputStream inputStream = request.getInputStream(); * OutputStream: * ServletOutputStream outputStream = response.getOutputStream(); * Reader:字符流 * BufferedReader reader = request.getReader(); * Writer: * PrintWriter writer = response.getWriter(); 5.4 乱码问题 如果中文有乱码,需要配置字符编码过滤器,且配置在其他过滤器之前,如(Hi支持REST风格的filter:HiddenHttpMethodFilter),否则不起作用,因为字符编码过滤器是在在第一次获取请求参数之前启动,而其他filter源码中可能回有获取请求参数的代码,例如HiddenHttpMethodFilter源码。 (思考method=”get”请求的乱码问题怎么解决?:改server.xml;在8080端口处URIEncoding=“UTF-8”)
<!-- 配置字符集 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
//encoding:指定解决POST请求乱码
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
//顺带解决响应乱码
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/\*</url-pattern>
</filter-mapping>
- 数据输出 6.1 Map、Model、ModelMap 实际上都是调用的 BindingAwareModelMap(隐含模型),将数据放在请求域(requestScope)中进行转发,用EL表达式可以取出对应的值。
/**
- SpringMVC除过在方法上传入原生的request和session外还能怎么样把数据带给页面
- 1)、可以在方法处传入Map、或者Model或者ModelMap。
-
给这些参数里面保存的所有数据都会放在请求域中。可以在页面获取
success.xml
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
pageScope: ${
pageScope.msg}
requestScope : ${
requestScope.msg}
sessionScope: ${
sessionScope.msg}
applicationScope: ${
applicationScope.msg}
</body>
</html>
OutputController: /**
- SpringMVC除过在方法上传入原生的request和session外还能怎么样把数据带给页面
- 1)、可以在方法处传入Map、或者Model或者ModelMap。
-
给这些参数里面保存的所有数据都会放在请求域中。可以在页面获取。
- 关系:
-
Map,Model,ModelMap:最终都是BindingAwareModelMap在工作;
-
相当于给BindingAwareModelMap中保存的东西都会被放在请求域中;
-
ModelMap继承了Map ExtendedModelMap继承ModelMap,实现Model接口 BindingAwareModelMap继承ExtendedModelMapMap 为jdk中的一个接口,Model 为spring中的一个接口
-
Map(interface(jdk)) Model(interface(spring))
-
|| //
-
|| //
-
\/ //
-
ModelMap(class) //
-
\\ //
-
\\ //
-
ExtendedModelMap
-
||
-
\/
-
BindingAwareModelMap
- 2)、方法的返回值可以变为ModelAndView类型;
-
既包含视图信息(页面地址)也包含模型数据(给页面带的数据);
-
而且数据是放在请求域中;
-
request、session、application;
/** * 一、Map::一个接口 * @param model * @return */
@Controller
public class OutputController {
@RequestMapping("/handle01")
public String handle01(Map