• SpringMVC


    SpringMVC

    1 Overview

    学习方法 课程说明 秦老师课前说的:

    SE 入门, 能看懂代码

    Web 框架在精简它

    框架 按正常, 这里是要从官网文档自学的, 不能再被老师带. 锻炼自学能力, 锻炼笔记能力, 锻炼项目能力

    SSM整合, 相当于在Web阶段的项目

    Spring IoC和AOP特别重要, 要再复习

    SpringMVC中也有个很重要的东西, 执行流程

    博客很重要, 工作时如果没有对应文档, 可能会崩溃

    版本: 老师用5.1.9, 我自己选用了5.2.0

    1.1 MVC

    模型(DAO service) | 视图(jsp) | 控制器(Servlet)

    后端很多特别牛批的控制器, 很多底层也都是Servlet

    职责

    Controller 1. 取得表单数据 2. 调用业务逻辑 3. 转向指定页面

    Model 1. 业务逻辑 2. 保存数据状态

    View 显示页面

    pojo:

    • vo: 视图层的实体类对象, 更灵活
    • dto: 数据传输时的对象
    • ...

    面试: 你的项目的架构是设计好的还是演进的??

    坑 一般都是演进的. 才合理. 阿里巴巴, MySQL --> AliSQL --> AliRedis

    所有项目一般都是All in one --> 微服务

    1.2 SpringMVC

    为什么要用它呢?

    • 轻量, 易学
    • 高效地, 基于请求响应的框架. (不是以事件为驱动)
    • 可与SpringFramework无缝集成
    • 约定优于配置
    • 功能强大, 支持: RESTful | 数据合法验证 | 异常处理 | 拦截器 ...
    • 市占率高

    RESTful, 不需要问号拼接参数

    1.3 基本原理 执行流程

    A - DispatcherServlet

    Spring的web框架围绕 DispatcherServlet 设计

    作用: 转发调度 ,将请求分发到不同"处理器"

    本质: 还是Servlet, 如下图

    ![image-20200422105032987](D:微云同步助手364291826同步文件夹知识库10 - md文库 秦疆老师框架SpringMVC.assetsimage-20200422105032987.png)

    ![image-20200421214015127](D:微云同步助手364291826同步文件夹知识库10 - md文库 秦疆老师框架SpringMVC.assetsimage-20200421214015127.png)

    中文版

    image-20200422111900346

    秦老师的图

    image-20200422114808087

    基本原理 - 简述: (based on 老师公众号)

    1. DispatcherServlet, 代表FrontController, 是整个SpirngMVC的"控制中心". 用户发出request, DS接收请求. 解析URL:
      • 例如: http://localhost:8080/SpringMVC/hello
      • http://localhost:8080 - 服务器域名端口
      • /SpringMVC - 部署在服务器上的具体web站点
      • /hello - 控制器
      • 综述: 请求位于服务器上"SpringMVC站点"的"hello"控制器
    2. HandlerMapping根据url中信息, 中众多注册过的Handler们中找具体的
    3. HandlerExecution (理解不太深刻), 主要作用是根据url查找控制器hello
    4. HandlerAdapter按特定规则执行Handler, Handler再让具体的Controller执行
    5. Controller调用执行我们写的业务代码, 得到数据, 存入ModelAndView对象, 并把该对象返回给Adapter, 再给DS
    6. DS调用ViewResolver解析mv对象中的"逻辑视图名", 同时将数据渲染给这个具体的View
    7. DS通过逻辑视图名, 找到渲染好的View, 呈现

    摘自老师: 没有笨人只有懒人

    基本原理 - 个人理解:

    HandlerMapping 是众多Handler们的映射器 注册中心, 通过它找到具体的Handler的信息, 把信息告诉给DS, DS再通过Adapter调用具体的handler, 也就是我们写的Controller

    ModelAndView 是Controller方法的返回值, 理解可以认为"给前端带个需要的值, 并且指定哪个页面文件"

    ViewResolver 作用

    1. 提取mv中model中的数据
    2. 解析mv中指定的view名字信息
    3. 拼接前缀路径+视图名字+后缀, 找到对应view
    4. 将数据渲染到view中
    5. 个人理解: VR是从MandV中提取出数据和指定view信息, 再把两者结合(渲染), 丢给DS, DS展现..ok

    B - 补充: Maven资源过滤问题

    Maven存在资源过滤问题, 经常出现xml文件编辑后不能正常out到target中, 可以在parent module的pom.xml中添加以下代码来解决:

    <build>
       <resources>
           <resource>
               <directory>src/main/java</directory>
               <includes>
                   <include>**/*.properties</include>
                   <include>**/*.xml</include>
               </includes>
               <filtering>false</filtering>
           </resource>
           <resource>
               <directory>src/main/resources</directory>
               <includes>
                   <include>**/*.properties</include>
                   <include>**/*.xml</include>
               </includes>
               <filtering>false</filtering>
           </resource>
       </resources>
    </build>
    

    1.4 RESTful

    (已经比较熟悉了, 这里只补充一些)

    作用:

    • 简洁, 显而易见
    • 高效 (支持缓存)
    • 可能有一定安全性, 因为url上可以避免暴露太多后台代码信息 (秦老师看法)

    注意点:

    • requestMapping有相同url, 但接收请求的method不同的 (一个get 一个post), 则会根据实际请求方式不同自动匹配
    • 别忘了@PathVariable

    1.5 小黄鸭调试法

    向自己, 如同向他人一样, 解释一下代码的作用 流程. 说到一半可能就明白了

    2 Hello SpringMVC

    2.1 通过代码理解: XML

    手动配置各个组件, 用Spring + SpringMVC实现一次HelloWorld!

    1. 确保Maven中webmvc的依赖正确导入, 确保projectStructure > artifact > 中依赖都正确

    2. 准备好一个SpringFramework的核心配置文件: springmvc-servlet.xml, in resources目录(classpath:)

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd">
      
      </beans>
      
    3. 配置DispatcherServlet: in web.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
               version="4.0">
      
          <!--配置DS-->
          <servlet>
              <servlet-name>springmvc</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <!--DS需要绑定Spring的核心配置文件-->
              <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:springmvc-servlet.xml</param-value>
              </init-param>
              <!--启动级别: 1-->
              <load-on-startup>1</load-on-startup>
          </servlet>
          <!--斜杠和斜杠* 有区别: 斜杠只匹配请求,斜杠*匹配请求+也包括jsp文件-->
          <servlet-mapping>
              <servlet-name>springmvc</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      

      注意:

      <url-pattern>

      • / - 只匹配请求, 不匹配.jsp文件
      • /* - 不光匹配请求, 也匹配文件
    4. 配置HandlerMapping, HandlerAdapter and ViewResolver, 交给Spring管理, in springmvc-servlet.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"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <!--HandlerMapping-->
          <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
      
          </bean>
      
          <!--HandlerAdapter-->
          <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter">
      
          </bean>
          <!--ViewResolver -->
          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
                id="internalResourceViewResolver">
              <!--前缀-->
              <property name="prefix" value="/WEB-INF/jsp"></property>
              <!--后缀-->
              <property name="suffix" value=".jsp"></property>
          </bean>
      
      </beans>
      
    5. Controller: HelloController.java

      package com.kuang.controller;
      
      import org.springframework.web.servlet.ModelAndView;
      import org.springframework.web.servlet.mvc.Controller;
      
      public class HelloController implements Controller {
          public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
              ModelAndView mv = new ModelAndView();
      
              /*这里写业务代码*/
              String result = "HelloSpringMVC";
              mv.addObject("msg",result);
      
              /*视图跳转*/
              mv.setViewName("test"); // 在视图解析器中拼接
      
              return mv;
          }
      }
      
      
    6. 配置Tomcat部署/s1并启动测试http://localhost:8080/s1/hello, 通过.

    2.2 通过代码理解: 注解

    1. 确保依赖都正常, 必须手动在projectStructure>artifact中添加lib目录, 并且把依赖也能输出进去!否则会404!

      image-20200422160930128

    2. 准备Spring的核心配置文件springmvc-servlet.xml. 这里和XML方式稍微有区别

      别忘了准备页面文件 web > jsp > hello.jsp

      <?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/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd
             http://www.springframework.org/schema/context
             https://www.springframework.org/schema/context/spring-context.xsd
             http://www.springframework.org/schema/mvc
             https://www.springframework.org/schema/mvc/spring-mvc.xsd">
      
          <!--自动扫描包,使指定的包下的注解生效-->
          <context:component-scan base-package="com.kuang.controller"></context:component-scan>
      
          <!--SpringMVC固定要写的 #######################开始-->
      
          <!--过滤静态资源的处理, 使S MVC不处理静态资源-->
          <mvc:default-servlet-handler></mvc:default-servlet-handler>
          <!--注解引擎-->
          <mvc:annotation-driven></mvc:annotation-driven>
          <!--ViewResolver-->
          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
                id="internalResourceViewResolver">
              <property name="prefix" value="/WEB-INF/jsp/"></property>
              <property name="suffix" value=".jsp"></property>
          </bean>
      
          <!--SpringMVC固定要写的 #######################结束-->
      
      
      </beans>
      
    3. web.xml中配置DServlet

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
               version="4.0">
      
          <!--配置DServlet-->
          <servlet>
              <servlet-name>springmvc</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <!--DS需要绑定Spring的核心配置文件-->
              <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:springmvc-servlet.xml</param-value>
              </init-param>
              <!--启动级别: 1-->
              <load-on-startup>1</load-on-startup>
          </servlet>
          <!--斜杠和斜杠* 有区别: 斜杠只匹配请求,斜杠*匹配请求+也包括jsp文件-->
          <servlet-mapping>
              <servlet-name>springmvc</servlet-name>
              <url-pattern>/</url-pattern>
          </servlet-mapping>
      </web-app>
      
    4. Controller.java

      package com.kuang.controller;
      
      import org.springframework.stereotype.Controller;
      import org.springframework.ui.Model;
      import org.springframework.web.bind.annotation.RequestMapping;
      
      @Controller // 被包扫描配置扫描到, 被Spring接管
      public class HelloSpring {
      
          @RequestMapping("/hello")
          public String hello(Model model){
              // 处理业务, 封装数据
              model.addAttribute("msg","Hello, SrpingMVC-annotaion!");
              return "hello"; // 会自动被视图解析器解析
          }
      
      }
      
      

    2.3 结果跳转

    A - ModelAndView方式

    1. 配置视图解析器

      页面 = [视图解析器前缀 + ] viewName [ + 视图解析器后缀]
      
    2. 对应Controller

      • 具体的controller是实现接口的. 返回的结果需要用MV对象封装
      // 伪代码
      public class HelloController implements Controller{
          public ModelAndView handleRequest(req, resp){
              mv.addObject(...);
              return mv;
          }
      }
      
      • controller如果是注解, 则要用Model.addAttribute()

        还有个ModelMap| ModelAndView, Model与之很像, 但更精简! 更常用Model

      @Controller // 被包扫描配置扫描到
      public class HelloController {
      
          @RequestMapping("/hello")
          public String hello(Model model){
              // 处理业务, 封装数据
              model.addAttribute("msg","Hello, SrpingMVC-annotaion!");
              return "hello"; // 会自动被视图解析器解析
          }
      
      }
      

    B - HttpServletResponse方式

    使用Servlet的API, 比较原始

    如果不用视图解析器, resp和req可以直接声明入方法形参, 直接可以用

    • 输出

      resp.getWriter().print("Hello world!");
      
    • 重定向

      resp.sendRedirect("/index.jsp");
      
    • 转发

      resp.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req, resp);
      

    C 重定向 转发

    • 无视图解析器

      return "redirect:/index.jsp";	// 重定向
      return "forward:/index.jsp";	// 转发
      
    • 有视图解析器

      return "redirect:/index.jsp";	// 与重定向, 与没有视图解析器相同
      return "index";	//转发
      

    2.4 请求数据处理

    • 如果前端name = 后端参数名name
      • 直接就可以了
    • 如果前端username != 后端参数名name
      • 借助@RequestParam("username") String name
      • 老师建议都加这个注解, 可以有效区分前端参数和普通参数
    • 如果前端正好符合后端的一个对象
      1. 后端可以直接用对象当参数
      2. 前提: 参数名要一致

    2.5 POST中文乱码

    手写Filter

    可解决, 注意过滤器的配置<url-pattern>要配置/*

    过滤器拦截路径配置 (重要, 易忘)

    • / - 所有请求, 不包含.jsp页面
    • /* - 所有请求, 包含.jsp页面

    Spring的Filter

    (与上类似)

    3 JSON

    JSON <--> JS 互转

        <script type="text/javascript">
    
            var v1 = {
                id:1001,
                name:"张三",
                age:18
            };
            var j = JSON.stringify(v1);
            console.log(j)
            var obj = JSON.parse(j);
            console.log(obj)
    
        </script>
    

    3.1 Java中生成JSON: Jackson

    可以借助Json解析工具, 如: Jackson | fastjson

    如何使用Jackson?

    1. 依赖jar

      <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
      <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.10.0</version>
      </dependency>
      
      
    2. Controller层

      package com.kuang.controller;
      
      import com.fasterxml.jackson.core.JsonProcessingException;
      import com.fasterxml.jackson.databind.ObjectMapper;
      import com.kuang.pojo.User;
      import org.springframework.stereotype.Controller;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.ResponseBody;
      
      @Controller
      public class JsonController {
      
          @RequestMapping(value="/json",produces = "application/json;charset=utf8")   //解决乱码问题
          @ResponseBody   // 不经过视图解析器解析 或者用类上@RestController
          public String testJson() throws JsonProcessingException {
              User user = new User(1001, "张三", 18);
      
              ObjectMapper mapper = new ObjectMapper();
              String stringJson = mapper.writeValueAsString(user);
              return stringJson;
          }
      }
      

    3.2 List to JSON

    // 输出结果是
    [{name:"dfkjdk",id:213},{},{}]
    

    3.3 Date to JSON

    • 传统手艺

      String dateSDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
      return mapper.writeValueAsString(dateSDF);
      
      // 结果 样式
      "2011-11-11 11:11:11"
      
    • Jackson的API

      1. 停用默认时间戳
      2. sdf格式传入
      objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
      mapper.setDateFormat(sdf);
      objectMapper.writeValueAsString(new Date());
      

    3.4 乱码问题

    • 可以如上述3.1中一个一个解决

    • 也可以统一解决

      统一解决, 在Spring的核心配置文件中配置

    3.5 FastJson

    from Alibaba

    String str = JSON.toJSONString(userList  user);	
    User user = JSON.parseObject(str, User.class);	
    
    JSONObject jsonObject = (JSONObject) JSON.toJSON(user);
    jsonObject.getString("name");
    User user = JSON.toJavaObject(jsonObject, User.class);
    

    4 AJAX

    4.1 试试

    jQuery.ajax(...)

    部分参数

    • url: 请求地址

    • type: 请求方式 GET POST 1.9.0之后用method

    • headers: 请求头

    • data: 要发送的数据

    • contenType: 即将发送给服务器的内容的编码类型(默认: application/x-www-form-urlencode)

    • async: 是否异步

    • timeout: 设置请求超时时间

    • beforeSend: 发送请求前执行的函数 全局

    • complete: 完成之后的回调函数

    • success: 成功之后执行的回调函数

    • error: 失败之后执行的回调函数

    • accepts: 通过请求头发送给服务器, 告诉服务器当前客户端可接受的数据类型

    • dataType: 将服务器返回的数据转换成指定类型

      • "xml": 将服务器返回的内容换成xml格式
      • "text": 普通文本
      • "html"
      • "script"
      • "json"
      • "jsonp"

    代码示例

    test.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
        <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.4.1.js"></script>
        <script type="text/javascript">
            function a(){
                $.post({
                    url:"${pageContext.request.contextPath}/a1",
                    data:{"name":$("#username").val()},
                    success:function(data){
                        alert(data);
                    }
                });
            };
    
    
        </script>
    </head>
    <body>
    <%--失去焦点时发起一个请求--%>
    用户名:<input type="text" id="username" onblur="a()">
    
    </body>
    </html>
    
    
    package com.kuang.controller;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.kuang.pojo.User;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @Controller
    public class JsonController {
    
        @RequestMapping(value = "/a1", produces="application/json;charset=utf8")
        @ResponseBody
        public void a1(String name, HttpServletResponse resp) throws IOException {    // 故意写成name
            System.out.println("a1:param-->" + name);
            if ("kuangshen".equals(name)){
                resp.getWriter().print("yes");
            } else {
                resp.getWriter().print("no");
            }
        }
    
        @RequestMapping(value = "/index2")
        public String index(){
            return "test2";
        }
    
    }
    
    

    4.2 结合JSON

    X BUG

    Artifact中一定要确保所有依赖都手动添加过! 别忘了中途添加的依赖!

  • 相关阅读:
    Markdown 列表、区块、代码(三)
    Markdown 标题、段落、文本(二)
    Markdown 简介(一)
    禅道学习笔记
    地图源改变之后mxd文件打开很慢的问题
    关于iReport报表的分页
    在VC项目中附加包含目录
    类静态成员变量的使用
    UI基础--UISlider&UIProgress
    UI基础--UISwitch
  • 原文地址:https://www.cnblogs.com/clzhang/p/12761148.html
Copyright © 2020-2023  润新知