SpringMVC详解

简介

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

参数绑定的含义

  1. 所谓的参数绑定,就是怎么样获取到前台页面传过来的值,通常是跟据参数名(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";
}
...
  1. 用标准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";
}
...
  1. 用注解@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";
}
...
  1. 通过注解@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";
}
...

映射方法的返回值类型

  1. 返回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文件

  1. 返回值是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文件上传

  1. 导入jar包

commons-fileupload-1.2.1.jar commons-io-1.3.2.jar

  1. 在springmvc配置文件中配置上传解析器

    
    
        
            20971520
        
        
        
    

  1. 编写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";
    }

}

  1. 编写jsp页面代码

    

采用流的方式上传文件

采用multipart提供的file.transfer方法上传文件

使用spring mvc提供的类的方法上传文件

Ajax和Controller的交互

  1. 导入jar包

jackson-annotations-2.9.2.jar jackson-core-2.9.2.jar jackson-databind-2.9.2.jar

  1. 在springmvc的配置文件中,加入json转换器



传入key-value键值对,输出json
  1. 在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);
        }
    })

  1. 在controller的方法返回值里,传给前台的数据格式是json
    @RequestMapping("tm")
    @ResponseBody
    public BYQ tm(BYQ byq2){
        System.out.println(byq2.getName());
        System.out.println(byq2.getPrice());
        return byq2;
    }

传入json,输出json

  1. 在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);
        }
    })

  1. 在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的配置文件中加入下面代码

    
    

你可能感兴趣的:(SpringMVC详解)