web.xml配置文件
<servlet>
<servlet-name>DispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springMVC.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>DispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
springMVC.xml配置文件
<context:component-scan base-package="com.young"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
bean>
HelloController处理器
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("hello")
public String hello(){
System.out.println("Hello SpringMVC");
return "index";
}
}
index.jsp代码,在与index.jsp同目录下存在文件"style.css"和图片"123.png"
<html>
<head>
<link rel="stylesheet" href="style.css" type="text/css"/>
head>
<body>
<h2>Hello World!h2>
<img src="123.png">
body>
html>
style.css代码
h2{
color: aqua;
}
问题:运行程序后图片无法显示,css文件没有生效,检查网络出现如下情况:style.css和123.png状态码为404
查看后台控制台日志,存在如下记录
13-May-2020 09:49:06.534 警告 [http-nio-8080-exec-4] org.springframework.web.servlet.DispatcherServlet.noHandlerFound No mapping for GET /style.css
13-May-2020 09:49:06.536 警告 [http-nio-8080-exec-5] org.springframework.web.servlet.DispatcherServlet.noHandlerFound No mapping for GET /123.png
原因:DispatcherServlet的映射路径为"/",Tomcat服务器中默认的Servlet(servlet-name为default)的映射路径也为"/",所以DispatcherServlet会覆盖Tomcat中默认的Servlet,处理除jsp之外的所有资源,导致静态资源无法被访问
Tomcat服务器中默认的Servlet
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
1.可以通过配置
<servlet-mapping>
<servlet-name>defaultservlet-name>
<url-pattern>*.htmlurl-pattern>
servlet-mapping>
2.在springMVC.xml配置文件中配置
<mvc:default-servlet-handler/>
<mvc:resources mapping="/" location="/"/>
<mvc:annotation-driven/>
分析这三个标签
标签会加载服务器默认的Servlet映射
配置该标签后会在SpringMVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler,它会像
一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果
不是静态资源的请求,才由DispatcherServlet继续处理。
如果Web应用服务器默认Servlet名称不是"default",则需要通过default-servlet-name属性指定
但是只配置该标签和RequestMapping注解会产生冲突,导致静态资源可以被访问,但是动态资源无法被访问
此时需要配置 来开启注解驱动,该标签功能强大,但在此处的作用只是使注解生效
对于 标签可以使任何地方的静态资源都被访问
在之前客户端只能访问webapp目录下的静态资源,而无法访问WEB-INF目录下的静态资源
通过mapping属性配置映射路径,"/"代表webapp目录,如果想要访问该目录下的所有子目录中的静态资源,可配置"/**",如果只想访问webapp目
录下的WEB-INF目录,可配置"/WEB-INF/";location代表访问路径,"/"为最大范围。
通常情况下只需要配置
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
@RequestMapping注解可以将Java方法配置为可以供客户端访问的资源
@RequestMapping("/hello")
public String hello(){
System.out.println("Hello SpringMVC");
return "index";
}
value属性
value属性和path属性是相同的,值为数组类型,制定请求的映射路径
关于映射路径是否加上"/"
有无"/"均可,建议加上
加"/"和不加"/"都表示从应用程序根目录( //http://localhost:8080/项目名称/ )下寻找
method属性
RequestMethod[] method() default {};
method属性可以指定客户端提交的方式,值是RequestMethod类型的数组,默认get和post两种请求都可以访问
RequestMethod是一个枚举类型,值有GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS,TRACE
如果指定了method值为"{RequestMethod.POST}",如下所示
@RequestMapping(value = "/hello",method = {RequestMethod.POST})
如果客户端发送请求的请求方式为GET,那么网页页面会显示如下信息:
HTTP Status 405 – 方法不允许
Type Status Report
消息 Request method 'GET' not supported
描述 请求行中接收的方法由源服务器知道,但目标资源不支持
通常用于文件上传等需要指定请求方式的操作中
浏览器表单提交默认只支持get和post提交方式,如果想要使用其他6种提交方式,首先需要配置过滤器,使SpringMVC会对请求资源判断
web.xml文件中配置过滤器
<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>
在处理器中增加处理请求方式的方法
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
public class HelloController {
@RequestMapping(value = "/hello",method = {RequestMethod.POST,RequestMethod.GET})
public String hello(){
System.out.println("Hello SpringMVC");
return "index";
}
@RequestMapping(value = "/hello",method = {RequestMethod.DELETE})
public void delete(HttpServletResponse response) throws IOException {
System.out.println("Hello SpringMVC delete");
response.getWriter().print("{success:true}");
}
}
在表单中增加一个隐藏表单域
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
head>
<body>
<form action="/hello" method="post">
<input type="hidden" name="_method" value="Delete"/>
<input type="submit" value="测试delete提交方式">
form>
body>
html>
运行程序发送请求,就会执行delete方法中的逻辑。
设置不同的method属性的值,对于同一个请求资源,但是不同的提交方式时,就会对应不同的处理逻辑
params属性
String[] params() default {};
params属性的值为一个字符串数组,用于限制客户端提交数据的请求参数
如果在hello方法中配置params属性,如下所示
@RequestMapping(value = "/hello",params = {"id"},method = {RequestMethod.POST,RequestMethod.GET})
如果客户端在请求"/hello"路径时没有携带请求参数"id",网页页面会出现如下异常:
HTTP Status 400 – 错误的请求
Type Status Report
消息 Parameter conditions "id" not met for actual request parameters:
描述 由于被认为是客户端对错误(例如:畸形的请求语法、无效的请求信息帧或者虚拟的请求路由),服务器无法或不会处理当前请求。
如果params = {"id","name"},那么请求需要两个请求参数id和name
如果params = {"id=1","name"},那么请求需要两个请求参数id和name,且参数id的值为1
如果params = {"id!=1","name"},那么请求需要两个请求参数id和name,且参数id的值不为1
@RequestMapping注解还可以标注在类上
以上"/hello"这个映射路径可能存在于多个Controller中,为了区分各个Controller中的相同的映射路径,可以在类上用@RequestMapping标注,如下:
@RequestMapping("/Hello")
此时在客户端中访问该资源的映射路径为"/Hello/hello"。
@RequestMapping还支持ant配置,用处不多,了解即可
? - 匹配任意单个字符
@RequestMapping("/user/?") 如:/user/a
* - 匹配任意数量字符(含0个)
@RequestMapping("/user/*") 如:/user/abc
** - 匹配任意数量目录(含0个)
@RequestMapping("/user/**/save") 如:/user/abc/ab/ef/save
@PathVariable可以在方法的参数上获取映射路径中占位符中的参数的值,从而在方法中可以访问这个值
@RequestMapping(value = "/hello/{id}",method = {RequestMethod.POST,RequestMethod.GET})
//将映射路径中的占位符"{id}"中id的值传给hello方法的参数id
public String hello(@PathVariable("id") Integer id){
System.out.println("Hello SpringMVC "+id);
return "index";
}
index.jsp代码
<html>
<head>
<link rel="stylesheet" href="style.css" type="text/css"/>
head>
<body>
<h2>Hello World!h2>
<img src="123.png">
body>
html>
出现问题:使用@PathVariable注解时,index.jsp界面中引用的静态资源无法被访问
检查浏览器网络得:目录结构发生了改变,为程序中引用静态资源使用的是相对路径,在当前项目的根路径下的hello/路径下是找不到index.jsp页面中引用的静态资源的
解决方法:我们可以在引用资源时使用绝对路径来解决这个问题
index.jsp代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
<head>
<link rel="stylesheet" href="<%=basePath%>style.css" type="text/css"/>
head>
<body>
<h2>Hello World!h2>
<img src="<%=basePath%>123.png">
body>
html>
@SessionAttribute注解应用在方法的参数上
@SessionAttributes建议应用在类上
HelloController处理器
import com.alibaba.fastjson.JSON;
import com.young.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
@SessionAttributes("user")
@RequestMapping("/Hello")
public class HelloController {
//模拟登陆
@RequestMapping("/login")
//如果方法没有返回字符串,那么客户端发送请求后,会自动跳转至以方法名为名称的.jsp页面,即"login.jsp"
public void login(User user){
System.out.println("登陆成功");
}
//模拟修改数据
@RequestMapping("/edit")
public void edit(@SessionAttribute("user") User user){
System.out.println("session中的用户:"+ JSON.toJSONString(user));
}
}
User实体类
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
在请求/login时增加参数username=aaa&password=aaa,会将这些数据封装为实体类User的对象user中,根据@SessionAttributes注解中的value
值将该对象会被存储进Session域中。
再请求/edit时可以使用@SessionAttribute注解将Session域中的值赋给方法中的参数。
注意:
如果有多个方法中都有user参数名,以最后一次存储进Session域中的对象为准。如果只想让login方法参数中的对象放在session中,那么需要让
这个登陆方法的参数与众不同,比如:loginUser_session。