入门
springMVC是处在控制层的一个地位,最原始的东西是servlet,后来发展出了struts框架,现在是使用SpringMVC,但是这几个都是处理控制层的框架。
SpringMVC与struts2的区别
springMVC
与struts2
都是controller
层的一个框架,对于MVC
的框架主要作用就是以下的几个方面。
- 拦截请求地址
- 将请求地址映射到某一个处理器
- 获得结果
- 将结果进行渲染,返回给视图
springMVC
与struts2
的具体比较信息如下:
对比项目 | SpringMVC | Struts2 | 优势 |
---|---|---|---|
国内市场情况 | 有大量用户,一般新项目启动都会选用springmvc | 有部分老用户,老项目组,由于习惯了,一直在使用 | 国内情况,springmvc的使用率已经超过Struts2 |
框架入口 | 基于servlet | 基于filter | 本质上没太大优势之分,只是配置方式不一样 |
框架设计思想 | 控制器基于方法级别的拦截,处理器设计为单实例 | 控制器基于类级别的拦截, 处理器设计为多实例 | 由于设计本身原因,造成了Struts2,通常来讲只能设计为多实例模式,相比于springmvc设计为单实例模式,Struts2会消耗更多的服务器内存 |
参数传递 | 参数通过方法入参传递 | 参数通过类的成员变量传递 | Struts2通过成员变量传递参数,导致了参数线程不安全,有可能引发并发的问题 |
与spring整合 | 与spring同一家公司,可以与spring无缝整合 | 需要整合包 | Springmvc可以更轻松与spring整合 |
使用springMVC的一个小案例
controller层
package top.twolovelypig.controller;
@Controller
public class HelloWorld {
@RequestMapping("welcome")
public String hello() {
return "success";
}
}
- 在浏览器中只需要输入
http:localhost:8080/项目名称/welcome
就会跳转到这里,这里返回的是一个字符串,其实这个字符串就是返回的jsp页面的名称,只是在下面的springMVC
配置文件中配置了视图解析器,也就是加上了前缀和后缀。最终返回的内容其实是前缀+success+后缀
。
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>01springMVC</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载spring核心配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<!-- 配置拦截路径 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 上面有一步是加载
springMVC
的核心配置文件,如果是使用默认的文件名以及路径可以使用配置,默认的路径是在WEB-INF
下面,默认的文件名是servlet-name里面的值-servlet.xml
,比如在上面的web.xml中配置的的值是springmvc,那么默认的配置文件名就是springmvc-servlet.xml - 配置拦截路径的时候这里使用的是
/
,也就是拦截一切请求,即所有的请求都是交给springMVC来处理,也就是再controller
中使用RequestMapping
这种注解形式的路径,如果配置的是*.action,那么就是所有的以action
结尾的请求都会被拦截交给springMVC
来处理。 - 如果是使用的eclipse并且配置了sts插件或者是使用的sts,那么上面web.xml中的配置可以一键生成,使用alt+/展开提示,找到有dispatcher的那个就可以了,生成好需要修改的有spring配置文件的路径以及
springMVC.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 配置@Controller处理器,包扫描器 -->
<context:component-scan base-package="top.twolovelypig.controller"/>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
RequestMapping的配置(不使用对象)
多级路径
不使用通配符
上面controller层的代码如下:
package top.twolovelypig.controller;
@Controller
public class HelloWorld {
@RequestMapping("welcome")
public String hello() {
return "success";
}
}
这里配置RequestMapping可以配置多级,下面的几种形式都是可以的
package top.twolovelypig.controller;
@Controller
@RequestMapping("HelloWorld")
public class HelloWorld {
@RequestMapping("welcome")
public String hello() {
return "success";
}
}
像这种形式访问路径就是http://localhost:8080/项目名称/Helloworld/welcome
,还可以是下面的这种形式。
package top.twolovelypig.controller;
@Controller
@RequestMapping("HelloWorld")
public class HelloWorld {
@RequestMapping("welcome/abc")
public String hello() {
return "success";
}
}
此时访问路径是http://localhost:8080/项目名称/Helloworld/welcome/abc
使用通配符
对于目录还可以使用通配符形式,主要有以下几种类型
-
*
,一个星号表示是任意字符,比如下面的代码package top.twolovelypig.controller; @Controller public class HelloWorld { @RequestMapping("welcome/*/abc") public String hello() { return "success"; } }
这里表示请求路径中开始是welcome,最后是abc,在这之间的可以是任意字符,下面这些请求路径都是合法的。
http://localhost:8080/项目名/welcome/asheib/abc
-
http://localhost:8080/项目名/welcome/asgerhre/abc
等
-
**
中间含有两个星号表示的是任意目录,也就是中间可以有任意层级,如果welcome与abc之间是两个星号的话下面的请求路径都是合法的http://localhost:8080/项目名/welcome/asheib/asg/agre/agr/abc
http://localhost:8080/项目名/welcome/asheib/asg/agre/abc
-
?
这里使用的问号表示是单个字符,还是上面的代码示例,如果welcome与abc之间是一个问号来表示那么下面的请求路径是合法的http://localhost:8080/项目名/welcome/a/abc
http://localhost:8080/项目名/welcome/k/abc
配置提交方式
RequestMapping中还可以配置其余参数,比如下面的代码
@Controller
public class HelloWorld {
@RequestMapping(value="welcome", method=RequestMethod.POST)
public String hello() {
return "success";
}
}
这里配置了method是post提交方式,也就是除了映射路径要对之外,提交的还必须是post方式才可以,比如下面的提交方式就是不行的。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="welcome">hello</a>
</body>
</html>
因为超链接默认是get提交方式,与我们配置吃不符合,所以不能被拦截。
此时就需要使用form提交,并且手动配置提交方式为post提交。
<body>
<a href="welcome">hello</a>
<form action="welcome" method="post">
<input type="submit">
</form>
</body>
在form当中手动配置了method属性为post,此时就可以被拦截到。
配置提交参数
除了提交方式之外还可以配置提交的参数。
@Controller
public class HelloWorld {
@RequestMapping(value="welcome", method=RequestMethod.POST, params= {"name", "age"})
public String hello() {
return "success";
}
}
提交参数是通过params来设置的,这里配置了name和age,也就是提交参数中必须要name属性和age属性,否则就不会被拦截到。如果还是之前那个空的form来提交就不会被拦截到,此时需要将那个form修改为如下形式
<body>
<a href="welcome">hello</a>
<form action="welcome" method="post">
<input name="name">
<input name="age">
<input type="submit">
</form>
</body>
还可以更严格一点是配置值,比如在controller中配置如下形式
@Controller
public class HelloWorld {
@RequestMapping(value="welcome", method=RequestMethod.POST, params= {"name=hello", "age"})
public String hello() {
return "success";
}
}
此时就算form当中有name参数但是如果name的值如果不是hello也是不行的,所以需要修改这种形式才可以被正确拦截到。
除了这些之外还可以配置其余参数,比如请求头之类的。
配置@PathVariable动态获取参数
如果是get请求之前是可以在请求路径后面加上加上问号来传递参数到后台,然后在后台可以通过request.getParamater()来获取传递过去的参数,在springMVC中可以通过@PathVariable来动态传递参数
jsp页面
<body>
<a href="welcome/hello/神奇">hello</a>
</body>
a标签吃一个get请求,这里的welcome是我们请求的路径,后面两个是我们传递的参数。
后台controller
@Controller
public class HelloWorld {
@RequestMapping(value="welcome/{name}/{age}")
public String hello(@PathVariable("name") String name, @PathVariable("age") String age) {
System.out.println(name);
System.out.println(age);
return "success";
}
}
可以看到在这里我们在welcome后面拼接了两个参数,大括号里面的是参数名,使用这种方式需要注意的是需要与@PathVariable注解结合起来使用,比如我们接受的第一个参数是name,在方法的形参前面的@PathVariable注解就需要写name,当然也可以在第二个参数位置写,位置可以不按照顺序,但是名称需要对应起来。
用@requestParam获取参数
上面说的参数是通过在路径后面拼接地址的方式来传递参数,如果不是在路径后面拼接,而是通过form表单来提交的话就可以通过@RequestParam来获取参数。
jsp页面
<form action="testParam" method="post">
<input type="text" name="uname" value="hello">
<input type="submit">
</form>
这样提交方式是post或者get都是可以的。
controller
@RequestMapping(value="testParam")
public String testParam(@RequestParam("uname") String name) {
System.out.println(name);
return "success";
}
在jsp页面中input的name属性是uname,这里@RequestParam也必须是uname,最终是将传过来的值赋值到name参数中。
SpringMVC处理各种参数的逻辑
- 前端发起一个请求,也就是给定一个路径
- 在controller中使用@RequestMapping映射找到对应的处理方法
- 在方法中使用注解获取传递过来的参数
将参数封装为对象
上面所讲的从前端带过来参数是直接获取的,但是如果参数有很多的时候一个一个的获取显然是不现实的,所以可以直接将参数封装到一个对象之中,SpringMVC
将参数封装到对象之中是很简单的,只需要满足下面几个条件即可。
- 表单中
name
属性必须与对象的属性名一致 - 如果有级联关联,除了保证
name
属性值与对象的属性名一致外还需要保证级联性
具体案例
Student对象
package top.twolovelypig.entity;
public class Student {
private int id;
private String name;
private Address address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return this.id + "," + this.name + "," + this.address.getHomeAddress() + "," + this.address.getSchoolAddress();
}
}
Address对象
package top.twolovelypig.entity;
public class Address {
private String homeAddress;
private String schoolAddress;
public String getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(String homeAddress) {
this.homeAddress = homeAddress;
}
public String getSchoolAddress() {
return schoolAddress;
}
public void setSchoolAddress(String schoolAddress) {
this.schoolAddress = schoolAddress;
}
}
jsp页面
<form action="testObject" method="post">
id:<input type="text" name="id" value="">
name:<input type="text" name="name" value="">
homeAddress:<input type="text" name="address.homeAddress" value="">
schoolAddress:<input type="text" name="address.schoolAddress" value="">
<input type="submit">
</form>
可以看到form
表单中name
属性值与实体中属性名一致,而且student
类中包含address
,所以对于address
类中的属性还需要加上arrdess
前缀。
controller
@RequestMapping(value="testObject")
public String testParam(Student student) {
System.out.println(student);
return "success";
}
在controller层中直接通过对象来接受值即可。
在springMVC中使用原生态的servlet-api
在servlet中的api中有一些方法是比较好用的,比如说HttpServletRequest和HttpServletResponse等,对于这些servlet-api如果想要在SpringMVC中使用也是很简单的,就是直接将这些作为参数传入SpringMVC的方法之中即可。比如:
@RequestMapping(value="testObject")
public String testParam(HttpServletRequest request, HttpServletResponse response,Student student) {
String name = request.getParameter("name");
System.out.println("通过request获取的name" + name);
System.out.println(student);
return "success";
}
配置过滤器增加对put与delete请求的支持
四种请求
这里的是四中请求方式其实对应的是增删改查四种操作
- get 获取的意思,也就是对应的是 查询
- post 提交的意思,也就是对应的是 新增
- delete 删除的意思,也就是对应的是 删除
- put 对应的是 修改
一般的浏览器其实是只支持get和post请求,也就是并不支持put以及delete请求,所以此处需要通过过滤器来实现将不支持的两种请求方式变得支持。
但是springMVC中使用这个过滤器的时候有两个条件需要先满足
- 我们使用的是post提交方式
- 含有隐藏域,形式为或者是
只有满足了这两个要求过滤器才会去执行。
过滤器的配置
在web.xml中需要配置一个过滤器,主要是记住过滤器的类名是HiddenHttpMethodFilter
<filter>
<filter-name>filtermethod</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>filtermethod</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
表单配置
上面已经说过如果是使用delete或者put提交方式,那么在表单中需要使用使用post提交,并且需要有隐藏域,该隐藏域需要满足两个条件,一个是name=“_method”,一个是value=“DELETE”或者value=“PUT”(delete或者put需要大写),也就是如下形式:
<form action="路径" method="post">
<input type="hidden" name="_method" value="DELETE">
</form>
由于映射是可以重复的,所以如果有相同的映射路径时可以通过method=RequestMethod.POST
或者method=RequestMethod.DELETE
来区别不同的映射路径。