简介
SpringMVC是一种基于Java的实现MVC设计模式的请求驱动类型的轻量级Web框架,使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发。
特性
1.简单、容易上手;
2.性能优异:jsp+servlet>Struts=SpringMVC>Struts2;
3.灵活、易于扩展;
4.易于和Spring容器整合;
SpringMVC程序示例
xml配置版
- 创建动态Web项目
- 导入spring的jar包,导入common-logging的jar包
- 为web项目引入SpringMVC框架,即在web.xml中配置SpringMVC的DispatcherServlet
springDispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:springmvc.xml
1
springDispatcherServlet
/
- 在src目录下创建SpringMVC的配置文件springmvc.xml,并加入如下代码
...
...
- 编写接受请求的控制器
//实现Controller接口,配置方式需要实现Controller类,相当于servlet继承HttpServlet
public class HelloController implements Controller{
//重写Controller接口的handleRequest方法
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws Exception {
//新建一个视图对象
ModelAndView mav = new ModelAndView();
//给视图对象里添加键值对形式的存储结构,相当于返回的键值对
mav.addObject("message", "hello springmvc");
//指定视图的jsp文件
mav.setViewName("hello.jsp");
return mav;
}
}
- 编写hello.jsp文件
获取值${message}
注解版
- 同上
- 同上
- 同上
- 在src目录下创建SpringMVC的配置文件springmvc.xml,并加入如下代码
...
...
- 编写接受请求的控制器
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloWorld {
/**
* 1. 使用RequestMapping注解来映射请求的URL,写在方法上面,一个请求对应一个方法
* 2. 返回值会通过视图解析器解析为实际的物理视图, 会做如下解析
* 通过prefix+returnVal+suffix 这样的方式得到实际的物理视图,然后会转发操作
* "/WEB-INF/views/success.jsp"
*/
@RequestMapping("/helloworld")
public String hello(){
System.out.println("hello world");
return "success";
}
}
- 同上
SpringMVC映射规则
二级映射
在类上和方法上同时注解@RequestMapping,相当于地址栏里有两级的地址
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("one")
public class TestController {
@RequestMapping("two")
public String test(){
return "index";
}
}
//如上注解后,映射地址为:http://localhost:8080/xx/one/two
Method类型选择接受
@RequestMapping注解括号里,有method属性作为对提价类型的选择接受
@RequestMapping(value="/getName",method={RequestMethod.GET, RequestMethod.POST})
//如果没有指定method,则默认为所有请求类型都接受
参数规则匹配
在响应请求的时候,对提交的参数规则进行验证,如果不符合设置的规则,则不接受请求
- param1=value1 - 请求中必须包含该参数和指定值
- param2 - 请求中必须包含该参数,值任意
- !param3 - 请求中必须不包含该参数\
@RequestMapping(value="/getName",method=RequestMethod.GET,params={"id=123","name","!age")
//上述规则定义了,只能响应get请求,并且请求的参数必须包含id=123,必须包含name,不能包含age
//根据上述规则此地址合法:http://localhost:8080/xx?id=123&name=abc
参数绑定的含义
- 所谓的参数绑定,就是怎么样获取到前台页面传过来的值,通常是跟据参数名(key)来获取值;
- 绑定页面传值的key值到映射方法的参数上,如下程序所示
//页面端提交请求的程序
$.post("../hc.v",
{
name : "shoji",
price : "8888"
},
function(d) {
alert(d);
}
)
//后台响应上面ajax的post请求的代码
//通过两段代码里“name”和“price”的相同,把“shouji”和“8888”传到hc方法里
//问号传值的方式同样适用 ?name=shoji&price=8888
...
@RequestMapping("hc")
public String hc(String name,String price){
return "test";
}
...
- 用标准PO属性来进行绑定
- 页面端提交请求的js代码同上
//新建一个标准的PO,同时当前类的属性名应该跟前台代码里的KEY对应上
public class PO{
private String name;//和key值一样
private Stirng price;//和key值一样
//省略各自的set get
}
//后台响应上面ajax的post请求的代码
//通过PO里的“name”和“price”属性名和前台js代码里的key相同,把“shouji”和“8888”传到hc方法里
//问号传值的方式同样适用 ?name=shoji&price=8888
...
@RequestMapping("hc")
public String hc(PO po){
//po.getName() 取出shoujie
//po.getPrice() 取出8888
return "test";
}
...
- 用注解@RequestParam来绑定
- 页面端提交请求的js代码同上
//后台响应上面ajax的post请求的代码
//通过注解里的“name”和“price”参数名和前台js代码里的key相同,把“shouji”和“8888”传到hc方法里
//问号传值的方式同样适用 ?name=shoji&price=8888
...
@RequestMapping("hc")
public String hc(@RequestParam("name") String p1,@RequestParam("price") String p2){
//p1 取出shoujie
//p2 取出8888
return "test";
}
...
- 通过注解@PathVariable
- 本注解把要传给后台程序的值,绑定在地址里
- 页面端提交请求的地址变为:dianhua/name/shoji/price/8888
//后台响应上面ajax的post请求的代码
//@RequestMapping注解的映射改变,地址里值的部分用{}括起来
//在方法的参数上使用注解@PathVariable
//通过PathVariable注解后面的“idvalue”和“pricevalue”和RequestMapping注解里{}部分相同,把“shouji”和“8888”传到hc方法里
@RequestMapping("dianhua/name/{idvalue}/price/{pricevalue}")
public String hc(@PathVariable String idvalue,@PathVariable String pricevalue){
//idvalue 取出shoujie
//pricevalue 取出8888
return "test";
}
...
映射方法的返回值类型
- 返回ModelAndView
@RequestMapping("/szw/jintiancailai")
public ModelAndView ccc(String namee) {
List list = new ArrayList();
list.add("zhiweizhi");
list.add("luchang");
System.out.println("hello name=" + namee);
ModelAndView mav = new ModelAndView();
mav.addObject("myList", list);
mav.addObject("mySize", "2");
mav.setViewName("first");
//first是一个页面文件的名字
//在springmvc的配置文件指定页面文件所在的路径是/WEB-INF/views/
//在springmvc的配置文件指定页面文件的类型是.jsp
//我们ModelAndView所展示的页面会做如下解析 prefix+setViewName+suffix
//即 /WEB-INF/views/first.jsp
return mav;
}
ModelAndView是springmvc框架提供一个包装界面jsp文件的类,常用的方法addObject和setViewName
addObject有两个参数,类型都是Object类型,第一个参数是key,第二个参数是值;主要用途,把java后的里的数据带到前台jsp页面上
setViewName有一个参数,类型是String;参数是jsp文件的名字;用途是告诉ModelAndView所展示的页面是哪个jsp文件
- 返回值是String
- 返回值里只有一个字符串
public String ddd() {
return "first";
}
//这样返回同上面程序注释的过程
- redirect和forward在返回值字符串前,并且redirect和forward和字串之间有一个冒号
public String eee() {
return "redirect:../first.jsp";
}
public String fff() {
return "forward:../first.jsp";
}
//这样返回,我们转去的地址不在被springmvc管理,需要转去的地址能直接在地址栏访问
- @ResponseBody注解
- 当返回值是String,并且方法上方有此注解时,返回的字符串将不在被解析为springmvc的视图(即jsp文件),会被直接以字符串展示在浏览器里
@RequestMapping("/test")
@ResponseBody
public String hhh() {
return "first";
}
//first将被输出到浏览器里
- 返回时void
- 需要人为在方法的参数列表里,加入request和response这两个参数,所有的操作依靠这两个参数来完成,非常类似标准的Servlet
public void ggg(HttpServletRequest req,HttpServletResponse rep) {
//标准servlet里怎么写,这段代码就怎么写
}
文件上传
Tomcat虚拟目录的配置
在tomcat的server.xml中,找到
节点,在开始和结束标签中写如下代码
如:
springMVC文件上传
- 导入jar包
commons-fileupload-1.2.1.jar commons-io-1.3.2.jar
- 在springmvc配置文件中配置上传解析器
20971520
- 编写Controller代码
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
/*
采用三种方式来接收上传文件,分别用三个方法试验
每个方法里,有程序执行时间记录
实际运用时,三者选其一
第一种最慢,第三种最快,一般选用第二种
*/
@Controller
public class FileController {
/*
* 通过流的方式上传文件
*
* @RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
*/
@RequestMapping("fileUpload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file) throws IOException {
// 用来检测程序运行时间
long startTime = System.currentTimeMillis();
try {
// 获取输出流
OutputStream os = new FileOutputStream("E:/" + new Date().getTime() + file.getOriginalFilename());
// 获取输入流 CommonsMultipartFile 中可以直接得到文件的流
InputStream is = file.getInputStream();
int temp;
// 一个一个字节的读取并写入
while ((temp = is.read()) != (-1)) {
os.write(temp);
}
os.flush();
os.close();
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("方法一的运行时间:" + String.valueOf(endTime - startTime) + "ms");
return "/success";
}
/*
* 采用file.Transto 来保存上传的文件
*/
@RequestMapping("fileUpload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file) throws IOException {
long startTime = System.currentTimeMillis();
String path = "E:/" + new Date().getTime() + file.getOriginalFilename();
File newFile = new File(path);
// 通过CommonsMultipartFile的方法直接写文件(注意这个时候)
file.transferTo(newFile);
long endTime = System.currentTimeMillis();
System.out.println("方法二的运行时间:" + String.valueOf(endTime - startTime) + "ms");
return "/success";
}
/*
* 采用spring提供的上传文件的方法
*/
@RequestMapping("springUpload")
public String springUpload(HttpServletRequest request) throws IllegalStateException, IOException {
long startTime = System.currentTimeMillis();
// 将当前上下文初始化给 CommonsMutipartResolver (多部分解析器)
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
// 检查form中是否有enctype="multipart/form-data"
if (multipartResolver.isMultipart(request)) {
// 将request变成多部分request
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
// 获取multiRequest 中所有的文件名
Iterator iter = multiRequest.getFileNames();
while (iter.hasNext()) {
// 一次遍历所有文件
MultipartFile file = multiRequest.getFile(iter.next().toString());
if (file != null) {
String path = "E:/springUpload" + file.getOriginalFilename();
// 上传
file.transferTo(new File(path));
}
}
}
long endTime = System.currentTimeMillis();
System.out.println("方法三的运行时间:" + String.valueOf(endTime - startTime) + "ms");
return "/success";
}
}
- 编写jsp页面代码
Ajax和Controller的交互
- 导入jar包
jackson-annotations-2.9.2.jar jackson-core-2.9.2.jar jackson-databind-2.9.2.jar
- 在springmvc的配置文件中,加入json转换器
传入key-value键值对,输出json
- 在ajax的提交请求里,传给后台的数据格式是kv对
//$.ajax $.post $.get 都是jquery的请求,需要引入jquery.js
//$.post和$.get都是$.ajax的简写方式
$.ajax({
type : "post",
url : "../tm.v",
contentType:"application/json; charset=utf-8",//请求成功后,后台返回的数据格式,即success : function(r)里“r”的格式
data : "name=shoji&price=8888",//此处就是标题中提到的传入key-value键值对
success : function(r) {
//r 直接就是jsonObject
alert(r.name);
}
})
- 在controller的方法返回值里,传给前台的数据格式是json
@RequestMapping("tm")
@ResponseBody
public BYQ tm(BYQ byq2){
System.out.println(byq2.getName());
System.out.println(byq2.getPrice());
return byq2;
}
传入json,输出json
- 在ajax的提交请求里,传给后台的数据格式是json串
$.ajax({
type : "post",
url : "../tm.v",
contentType:"application/json; charset=utf-8",
data:'{"name":"shouji","price":"8888"}',//此处就是标题中提到的传入的json格式串
success : function(r) {
//r 直接就是jsonObject
//如果返回的r是字符串,在调用r.price之前需要把字符串转为json对象,var jsonObject = JSON.parse(r);
alert(r.price);
}
})
- 在controller的方法返回值里,传给前台的数据格式是json,并且在方法的参数里接收的也是json串
//@ResponseBody注解和方法的返回值被置为BYQ,是为了返回值是json格式
//@RequestBody注解和方法的参数是BYQ类型,是为了接收前台提交过了的json格式
@RequestMapping("tm")
@ResponseBody
public BYQ tm(@RequestBody BYQ byq2){
System.out.println(byq2.getName());
System.out.println(byq2.getPrice());
return byq2;
}
restful
- 简介
体现在浏览器地址;每一个地址代表一种后台的资源(实例),地址里不能出现动词,具体的功能操作用提交method的类型来区分
- 映射模板
传统方式:http://localhost:8080/ssm/updateuser?id=123
restful: http://localhost:8080/ssm/user/123 通过这个地址看不出是增删改,具体操作下面来对应
- 提交方法类型对应(method的值)
get - 查询
post - 修改
put - 添加
delete - 删除
springmvc里对restful的支持
通过注解@PathVariable来支持rest风格的地址,详见
springmvc4以上的版本,提供注解@RestController来支持
当SpringMVC映射为/时,不需要被映射的地址处理方式
- 映射为/,即在web.xml中引入springmvc时,url-pattern标签的值为/,即网站下所有地址都被mvc拦截
...
springmvcservlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:mymvc.xml
springmvcservlet
/
...
- 解决静态资源被拦截的方法之一,在SpringMVC的配置文件中加入下面代码