springMVC记录

82 阅读7分钟

MVC是什么

MVC的全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范

image.png

url映射

使用注解来实现url的映射 比如使用get方法:@GetMapping("(url的地址)"),post方法:@PostMapping("(url地址)")等等 这些注解一般用在具体的方法上。在整个类上可以使用@RequestMapping("url")来对类的内部方法做一个统一的规范。除了有专门的方法mapping注解还有统一的注解,我们也可以在方法上使用@RequestMapping来实现对方法url的约束,只不过配置项略多。

@Controller
@RequestMapping("/um")
public class URLMappingController {
    @GetMapping("/g")
    //作用在方法上,不再区分get/post请求,该方法不仅要指明url地址还要指明请求的方法类型。
    //@RequestMapping(value="/g",method = RequestMethod.GET)
    @ResponseBody
    public String getMapping(@RequestParam("manager_name") String managerName , Date createTime){
        System.out.println("managerName:"+managerName);
        return "This is get method";
    }}

参数传参

如果前端传回的数据名称和对应方法参数中的名称一致,那么mvc会帮我们做自动映射,还会帮我们做类型转换,所以使用时要注意类型可以自动转换才行。

但有些情况下无法对应,比如xxx_xxxx和驼峰命名方法,这个时候我们需要在方法参数前使用@RequestParam注解,注解的内容就是前端传回的字段,该注解会把对应字段的值传给使用的参数中。
有时候一些参数可能会没有数据传回来,这时候我们仍然可以使用该注解设置默认值。


  public String getMapping(@RequestParam("manager_name") String managerName , Date createTime)
 
 //接受参数的字段名,没有的情况下的默认值
  @RequestParam(value="xxx",defaultValue = "aaa")
  

参数还可以是以类对象的形式存在,mvc会自动查找该类的属性中与传入的数据名一致的属性并注入值。如果此时参数中也有同名的参数那么mvc会都注入。我们也可以在传参的表单中指定类和类的属性进行传参。

方法是如何相应产生结果

使用@ResponseBody。

  1. 该方法直接产生响应体的数据,过程不涉及任何视图
  2. 该方法会产生标准字符串/json/xml等格式数据
  3. 可以被StringHttpMessageConverter影响

有时候我们可能会返回很多东西或者是一个页面,虽然使用@ResponseBody注解可以返回xml格式在网页上展现,但工程量太大,这时候我们可以使用ModelAndView来进行返回。

ModelAndView翻译过来就是”模型和视图“,可以理解成MVC架构中的”M“和”V“,其中包含”Model“和”view“两部分,主要功能是:

  1. 设置转向地址
  2. 将底层获取的数据进行存储(或者封装)
  3. 最后将数据传递给View

使用例子:

@GetMapping("/view")
    public ModelAndView showView(Integer userId){
    //创建方法,指定返回的jsp模版文件,下面注释的第一个会重定向,第二个不会
//        ModelAndView mav = new ModelAndView("redirect:/view.jsp");
//        ModelAndView mav = new ModelAndView("/view.jsp");
        ModelAndView mav = new ModelAndView();
        mav.setViewName("/um/view.jsp");
        User user = new User();
        if(userId == 1){
            user.setUsername("lily");
        }else if(userId == 2){
            user.setUsername("smith");
        }else if(userId == 3){
            user.setUsername("lina");
        }
        //向mav对象添加内部对象及其别名
        mav.addObject("u" , user);
        return mav;
    }

<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>I'm view page(/um/view.jsp)</h1>
    <hr>
    //调用mav中内部对象的属性
    <h3>Username:${u.username}</h3>
</body>
</html>

这种方法可以使前后端解耦,前端只知道可以调用什么对象的什么数据即可,后端只需要传入相应的数据即可。

使用ModelAndView有几点要注意:

  1. mav.addObject方法是将对象放入到当前的请求中
  2. modelandview默认是使用请求转发至页面
  3. 如果要使用重定向可以这样写:new ModelAndView("redirect:/view.jsp");(使用重定向addObject方法加入的数据无法被重定向)

在springmvc可以使用restful风格进行开发。

在平时的开发中,我们可以使用responseBody进行标注,使返回值可以被识别,但方法多了使用起来就很麻烦,这时候我们就可以对类使用@RestController注解,该注解会使所有类的方法都默认标注了@ResponseBody。

路径变量

路径变量就是在uri中传入的变量。 可以通过注解来获取uri中的变量。 如:

@PostMapping("/url/{id}")
public String fun(@PathVariable("id") Integer userId){}

简单请求和非简单请求

  1. 简单请求指标准结构的http请求,对应get和post
  2. 非简单请求指复杂要求的http请求,对应put、delete和扩展标准请求。
  3. 两者的最大区别是非简单请求发送请求前要发送预检请求。

使用非简单请求可以通过预检请求挡住不符合的请求减轻服务器的压力。

springmvc为put和delete提供了额外的表单过滤器来实现过滤。 在web.xml中进行过滤


 <filter>
 //名字,可以自定义
        <filter-name>formContentFilter</filter-name>
        //类,利用这个过滤器对put和delete提供支持
       <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    </filter>
    //对url进行过滤
    <filter-mapping>
        <filter-name>characterFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

对json进行序列化

可以使用jackson组件来帮助我们进行json的序列化实现。需要导入对应的dependent。

 <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.9</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.9</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.9</version>
        </dependency>
        
 

方法

//当我们使用了restcontroller或responsebody注解就会自动地将返回类转换为json字符串
 @GetMapping("/persons")
 //使用list集合获取多个类对象
   public List<Person> findPersons(){
       List list = new ArrayList();
       Person p1 = new Person();
       p1.setName("lily");
       p1.setAge(23);
       p1.setBirthday(new Date());

       Person p2 = new Person();
       p2.setName("smith");
       p2.setAge(22);
       p2.setBirthday(new Date());
       list.add(p1);
       list.add(p2);
       return list;
   }

同源和跨域的问题。

浏览器的同源策略:阻止一个域上的加载脚本去获取另一个域上的资源,只要协议、域名、端口有一点不同,就会看做是跨域。发送跨域时会在浏览器中看到Access-Control-Allow-Origin。

在html中有三项不受跨域的影响:

  1. <img> 显示远程图片
  2. <script> 加载远程的js
  3. <link> 加载远程的css

springmvc解决跨域问题

  • @CrossOrigin,coltroller跨域注解
  • <mvc:cros>,在配置文件中解决跨域配置的问题
//使用注解,内容是可以访问的域
@CrossOrigin(origins = {"http://localhost:8080","http://www.imooc.com"})
//允许所有的域都能访问,maxAge:设置预检请求的缓存时间。
@CrossOrigin(origins = "*",maxAge = 3600)
<mvc:cors>
//表名对应域名就会使用该配置项的配置
        <mvc:mapping path="/restful/**"
                     allowed-origins="http://localhost:8080,http://www.imooc.com"
                     max-age="3600"/>
    </mvc:cors>

两者都配置的情况下会以注解为基准。

拦截器 Intercepter

  • 拦截器用于对url前置和后置的过滤
  • 拦截器与fliter的作用相似,但实现方式不同
  • 拦截器基于springAOP实现的

拦截器的使用流程:

  1. maven配置依赖
  2. 实现HandlerIntercepter接口
  3. applicationContext配置过滤地址

1、

<dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            //设置作用范围,因为springmvc中的tomcat自带servlet-api,所以规定作用范围
            <scope>provided</scope>
        </dependency>

2、接口中有三个方法,使用时要重写这三个方法

public class MyInterceptor implements HandlerInterceptor {
//前置执行处理
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       System.out.println(request.getRequestURL() + "-准备执行");
//        response.getWriter().print("[]");
//return结果决定是直接返回还是继续向后执行
       return true;
   }
//目标资源已被springmvc处理了,目标资源被处理成功,但还没产生响应文本。这个时间段做的事情
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
       System.out.println(request.getRequestURL() + "-目标处理成功");
   }
//产生相应文本以后
   public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
       System.out.println(request.getRequestURL() + "-响应内容已产生");
   }
   

3、

在applicationcontext中的配置

<mvc:interceptors>
       <mvc:interceptor>
       //指定拦截的方法
           <mvc:mapping path="/restful/**"/>
           <bean class="com.imooc.restful.interceptor.MyInterceptor"/>
       </mvc:interceptor>
   </mvc:interceptors>
使用细则

1、如果不加配置,那么网页上所有的资源都会被拦截,包括图片、js、css等,这些资源一般不需要进行拦截,所以我们可以设置成不拦截这类资源。同时多个网址可以配置在同一个拦截器配置中。 所以实现可以如下:

        <mvc:interceptor>
            <mvc:mapping path="/restful/**"/>
            <mvc:mapping path="/webapi/**"/>
            //忽略的资源设置
            <mvc:exclude-mapping path="/**.ico"/>
            <mvc:exclude-mapping path="/**.jpg"/>
            <mvc:exclude-mapping path="/**.gif"/>
            <mvc:exclude-mapping path="/**.js"/>
            <mvc:exclude-mapping path="/**.css"/>
            //一般把静态资源放在同一个文件中,所以可以通过忽略对应文件夹来直接忽略
            <mvc:exclude-mapping path="/resources/**"/>
            <bean class="com.imooc.restful.interceptor.MyInterceptor"/>
        </mvc:interceptor>

如果配置了多个拦截器,那么执行顺序是如何?
前置请求会按照顺序执行,而后两种请求则是按倒序执行的。

image.png

springmvc的执行流程

D660B74085AB9644A2A6E51A4421AD3E.png

  1. 客户端发送请求给中央处理器
  2. 中央处理器通过处理器映射器获得处理器
  3. 处理器映射器给中央处理器返回一个具体的执行链(interceptor和controller)
  4. 向handrAdapter发起具体的执行请求
  5. handrAdapter根据handler的类型决定具体的执行方法
  6. 执行成功后依次返回modelandview
  7. 根据返回的view配置,选择对应的解析器
  8. 解析器返回对应的view对象(视图对象)
  9. 有了视图对象结合model中的数据进行渲染
  10. 渲染后得到html,返回给浏览器。