主頁 > 軟體設計 > 【Spring】SpringMVC

【Spring】SpringMVC

2021-02-06 10:49:55 軟體設計

1. 什么是 MVC

  • MVC是模型(Model)、視圖(View)、控制器(Controller)的簡寫,是一種軟體設計規范,

  • 是將業務邏輯、資料、顯示分離的方法來組織代碼,

  • MVC主要作用是降低了視圖與業務邏輯間的雙向偶合

  • MVC不是一種設計模式,MVC是一種架構模式,當然不同的MVC存在差異,

Model(模型):資料模型,提供要展示的資料,因此包含資料和行為,可以認為是領域模型或JavaBean組件(包含資料和行為),不過現在一般都分離開來:Value Object(資料Dao) 和 服務層(行為Service),也就是模型提供了模型資料查詢和模型資料的狀態更新等功能,包括資料和業務,

View(視圖):負責進行模型的展示,一般就是我們見到的用戶界面,客戶想看到的東西,

Controller(控制器):接收用戶請求,委托給模型進行處理(狀態改變),處理完畢后把回傳的模型資料回傳給視圖,由視圖負責展示,也就是說控制器做了個調度員的作業,

最典型的MVC就是JSP + servlet + javabean的模式,

在這里插入圖片描述

2. 第一個 Spring MVC 程式——配置版

2.1 新建一個 Maven 工程作為父工程,其 pom.xml 如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ice</groupId>
    <artifactId>spring-mvc</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>
</project>

之后在該專案下新建 module 即可

2.2 新建 module

在這里插入圖片描述

2.3 添加 web 支持

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

2.3 配置 web.xml,注冊 DispatcherServlet

<?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">

    <!--1.注冊DispatcherServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--關聯一個springmvc的組態檔:【servlet-name】-servlet.xml-->
        <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)-->
    <!--/* 匹配所有的請求;(包括.jsp)-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

2.4 撰寫 SpringMVC 的組態檔

<?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>

2.5 添加處理映射器

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

2. 添加 處理器配接器

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

2.7 添加 視圖決議器

<!--視圖決議器:DispatcherServlet給他的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
   <!--前綴-->
   <property name="prefix" value="/WEB-INF/jsp/"/>
   <!--后綴-->
   <property name="suffix" value=".jsp"/>
</bean>

2.8 撰寫業務 Controller

package com.ice.controller;


import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloController implements Controller {
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //ModelAndView 模型和視圖
        ModelAndView mv = new ModelAndView();

        //封裝物件,放在ModelAndView中,Model
        mv.addObject("msg", "HelloSpringMVC!");
        //封裝要跳轉的視圖,放在ModelAndView中
        mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
        return mv;
    }
}

2.9 撰寫 hello.jsp

在 WEB-INF檔案夾下新建jsp檔案夾,在其中新建 hello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
${msg}
</body>
</html>

2.10 注冊bean

<!--Handler-->
<bean id="/hello" class="com.kuang.controller.HelloController"/>

2.11 配置 Tomcat 測驗

在這里插入圖片描述


可能遇到的問題:訪問404
  1. 查看控制臺輸出,看一下是不是缺少了什么jar包,

  2. 如果jar包存在,顯示無法輸出,就在IDEA的專案發布中,添加lib依賴!

在這里插入圖片描述

  1. 重啟Tomcat 即可解決!

3. 第一個 Spring MVC 程式——注解版

3.1 新建 module

記住添加 web 支持,同時完善 maven 配置,解決資源過濾問題

<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>

3.2 配置 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">

   <!--1.注冊servlet-->
   <servlet>
       <servlet-name>SpringMVC</servlet-name>
       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
       <!--通過初始化引數指定SpringMVC組態檔的位置,進行關聯-->
       <init-param>
           <param-name>contextConfigLocation</param-name>
           <param-value>classpath:springmvc-servlet.xml</param-value>
       </init-param>
       <!-- 啟動順序,數字越小,啟動越早 -->
       <load-on-startup>1</load-on-startup>
   </servlet>

   <!--所有請求都會被springmvc攔截 -->
   <servlet-mapping>
       <servlet-name>SpringMVC</servlet-name>
       <url-pattern>/</url-pattern>
   </servlet-mapping>

</web-app>

/ 和 /* 的區別:

< url-pattern > / </ url-pattern > 不會匹配到 .jsp, 只針對我們撰寫的請求;即:.jsp 不會進入 spring 的 DispatcherServlet 類 ,

< url-pattern > /* </ url-pattern > 會匹配 *.jsp,會出現回傳 jsp 視圖時再次進入 spring 的 DispatcherServlet 類,導致找不到對應的 controller 所以報 404 404 404 錯,

3.3 添加 Spring MVC 組態檔

<?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 http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 自動掃描包,讓指定包下的注解生效,由IOC容器統一管理 -->
    <context:component-scan base-package="com.ice.controller"/>
    <!-- 讓Spring MVC不處理靜態資源 -->
    <mvc:default-servlet-handler />
    <!--
    支持mvc注解驅動
        在spring中一般采用@RequestMapping注解來完成映射關系
        要想使@RequestMapping注解生效
        必須向背景關系中注冊DefaultAnnotationHandlerMapping
        和一個AnnotationMethodHandlerAdapter實體
        這兩個實體分別在類級別和方法級別處理,
        而annotation-driven配置幫助我們自動完成上述兩個實體的注入,
     -->
    <mvc:annotation-driven />

    <!-- 視圖決議器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          id="internalResourceViewResolver">
        <!-- 前綴 -->
        <property name="prefix" value="/WEB-INF/jsp/" />
        <!-- 后綴 -->
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

3.4 創建 Controller

package com.ice.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/HelloController")
public class HelloController {

    //真實訪問地址 : 專案名/HelloController/hello
    @RequestMapping("/hello")
    public String sayHello(Model model){
        //向模型中添加屬性msg與值,可以在JSP頁面中取出并渲染
        model.addAttribute("msg","hello,SpringMVC");
        //web-inf/jsp/hello.jsp
        return "hello";
    }
    
}
  • @Controller 是為了讓Spring IOC容器初始化時自動掃描到
  • @RequestMapping 是為了映射請求路徑,這里因為類與方法上都有映射所以訪問時應該是 /HelloController/hello
  • 方法中宣告 Model 型別的引數是為了把 Action 中的資料帶到視圖中
  • 方法回傳的結果是視圖的名稱 hello,加上組態檔中的前后綴變成 WEB-INF/jsp/hello.jsp

3.5 創建視圖層

WEB-INF/jsp 目錄中創建 hello.jsp , 視圖可以直接取出并展示從 Controller 帶回的資訊

可以通過 EL 運算式取出 Model中存放的值,或者物件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SpringMVC</title>
</head>
<body>
${msg}
</body>
</html>

3.6 配置 Tomcat 運行

在這里插入圖片描述

4. Spring MVC

4.1 Spring MVC 的特點

  1. 輕量級,簡單易學
  2. 高效 , 基于請求回應的 MVC 框架
  3. 與 Spring 兼容性好,無縫結合
  4. 約定優于配置
  5. 功能強大:RESTful、資料驗證、格式化、本地化、主題等
  6. 簡潔靈活

4.2 Spring MVC 基本原理

Spring 的 web 框架圍繞 DispatcherServlet 設計,DispatcherServlet 的作用是將請求分發到不同的處理器,從Spring 2.5開始,使用Java 5或者以上版本的用戶可以采用基于注解的 @Controller 宣告方式,

Spring MVC 框架像許多其他 MVC 框架一樣, 以請求為驅動 , 圍繞一個中心 Servlet 分派請求及提供其他功能DispatcherServlet 實際上就是一個 Servlet (它繼承自 HttpServlet 基類)

在這里插入圖片描述

SpringMVC的原理如下圖所示:

當發起請求時被前置的控制器攔截到請求,根據請求引數生成代理請求,找到請求對應的實際控制器,控制器處理請求,創建資料模型,訪問資料庫,將模型回應給中心控制器,控制器使用模型與視圖渲染視圖結果,將結果回傳給中心控制器,再將結果回傳給請求者,

在這里插入圖片描述

4.3 Spring MVC 執行流程

4.3.1 作業原理

在這里插入圖片描述

圖為 Spring MVC 的一個較完整的流程圖,紅線部分表示要自己實作的,另外視圖決議器也要自己配置,

4.3.2 主要組件

  • 前端控制器(DispatcherServlet)

    接收請求,回應結果,回傳可以是 json,String 等資料型別,也可以是頁面(Model)

  • 處理器映射器(HandlerMapping)

    Spring mvc 使用 HandlerMapping 來找到并保存 url 請求和處理函式間的 mapping 關系

    DefaultAnnotationHandlerMapping 為例來具體看HandlerMapping 的作用,DefaultAnnotationHandlerMapping 將掃描當前所有已經注冊的 spring beans 中的@RequestMapping 注解以找出 url 和 handler method 處理函式的關系并予以關聯,

  • 處理器(Handler)

    就是我們常說的 Controller 控制器啦,由程式員撰寫

  • 處理器配接器(HandlerAdapter)

    可以將處理器包裝成配接器,這樣一個配接器就可以支持多種型別的處理器,Spring MVC通過HandlerAdapter來實際呼叫處理函式

    AnnotationMethodHandlerAdapter 為例,DispatcherServlet 中根據 HandlerMapping 找到對應的 handler method 后,首先檢查當前工程中注冊的所有可用的handlerAdapter,根據 handlerAdapter 中的 supports() 方法找到可以使用的 handlerAdapter,通過呼叫 handlerAdapter 中的 handle() 方法來處理及準備 handler method 中的引數及 annotation (這就是 spring mvc 如何將 reqeust 中的引數變成 handle method 中的輸入引數的地方),最終呼叫實際的 handle method,

    Spring 為什么要結合使用 HandlerMapping 以及 HandlerAdapter 來處理 Handler?

    符合面向物件中的單一職責原則,代碼架構清晰,便于維護,最重要的是代碼可復用性高,如 HandlerAdapter 可能會被用于處理多種 Handler,

  • 視圖決議器(ViewResovler)

    進行視圖決議,回傳view物件(常見的有JSP,FreeMark等)

4.3.2 作業原理

  1. 客戶端瀏覽器在發出一個請求之后,先決議主機名的 IP?? 嘗試連接,然后發送 HTTP 請求

  2. web 服務器接收到 HTTP 請求之后,會決議主機,決議背景關系,決議資源名,然后根據 sever.xml 找到引擎下的對應主機,找到對應的背景關系,找到對應的資源在哪里,再去讀對應 webapps 目錄下的應用,讀取 WEB-INF 下的 web.xml 檔案

  3. 這才正真開始!這時候的 request 其實還有點迷茫,因為還差那么一點,主機對應的具體應用找見了,但還沒有找到具體的哪個頁面,找到了組織,但還要具體找組織中哪個人去處理我問題,讀著讀著 web.xml,spring 突然跳出來,說:“交給我吧!”

    <!--Spring MVC 的大腦:DispatcherServlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--配置初始化引數,其作用是指定 Spring MVC 組態檔的位置和名稱-->
        <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)-->
    <!--/* 匹配所有的請求;(包括.jsp)-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    • <load-on-startup>是表示在容器在啟動的時候就加載 Servlet 實體,也就是說請求還沒來的時候,這個實體已經初始化了,實體緩沖池中有這個,當請求來的時候,直接交給該實體就可以,那么,其實它所做的作業無非就是把專案中的處理類都掃描之后,做一個映射,把具體的處理請求方法的 url 和方法名組成一個 Map,所以,Spring 的組態檔應該是在初始化的時候就被讀取了

      這里請求和處理類組成 Map 可以是組態檔配置 Bean,然后處理類繼承 Controller 介面重寫抽象方法,也可以用 @RequestMapping("/HelloController") 注解形式,將請求和 handler 一一對應,

    • DispatcherServlet 是一個 Servlet,init() 實體化之后,一定會接收請求,它應該也有自己的 service 方法,所對應的業務邏輯類似于流程圖,拿到請求中 url,然后 handleMapping 的 Map 集合中映射對應的處理方法,拿到結果之后,DispatcherServlet 就知道執行哪一個 controller,之后,就反射執行這個處理請求的方法,得到 ModelAndView,在之后,呼叫視圖決議器,給 viewName 加個前綴、后綴,回傳給DispatcherServlet,之后轉發給對應的頁面,Model 等價于Request,頁面從 Model 中讀取相應內容之后,回傳客戶端進行顯示,

    • 像攔截器這種硬編碼的內容在 DispatcherServletinit() 方法中就會被讀取加載了(DispatcherServlet 有默認的初始化策略函式),然后請求過來時,也會先執行 onFresh() 方法,添加一些動態請求資訊,方便后面作業流程中呼叫,

  4. DispatcherServlet 實體呼叫它的 doService() 方法,doService() 方法內部呼叫該實體的 doDispatch() 方法,在 doDispatch() 方法中:

    1. 呼叫 DispatcherServlet 實體的 getHandler() 方法,其內部呼叫 HandlerMappinggetHandler() 方法,回傳 HandlerExecutionChain 實體

      // DispatcherServlet 實體的 getHandler() 方法
      protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
          if (this.handlerMappings != null) {
              for (HandlerMapping mapping : this.handlerMappings) {
                  HandlerExecutionChain handler = mapping.getHandler(request);  //  HandlerMapping 的 getHandler() 方法
                  if (handler != null) {
                      return handler;
                  }
              }
          }
          return null;
      }
      

      HandlerMappinggetHandler() 方法不止回傳之前匹配的 handler,其內部會加載該請求需要經過的攔截器,一并封裝成 HandlerExecutionChain 物件回傳,

      protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
       HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                                      (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
      
       for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
           if (interceptor instanceof MappedInterceptor) {
               MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
               if (mappedInterceptor.matches(request)) {
                   chain.addInterceptor(mappedInterceptor.getInterceptor());
               }
           }
           else {
               chain.addInterceptor(interceptor);
           }
       }
       return chain;
      }
      
    2. 呼叫 DispatcherServlet 實體的 getHandlerAdapter() 方法,遍歷已有的 HandlerAdapter 實體,找到支持本次 handler 的 HandlerAdapter 實體并回傳

      protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
          if (this.handlerAdapters != null) {
              for (HandlerAdapter adapter : this.handlerAdapters) {
                  if (adapter.supports(handler)) {
                      return adapter;
                  }
              }
          }
          throw new ServletException("No adapter for handler [" + handler +
                                     "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
      }
      
    3. 執行 HandlerExecutionChain 實體的 applyPreHandle() 方法,其內部呼叫攔截器的 preHandle() 方法

      boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
          for (int i = 0; i < this.interceptorList.size(); i++) {
              HandlerInterceptor interceptor = this.interceptorList.get(i);
              if (!interceptor.preHandle(request, response, this.handler)) {
                  triggerAfterCompletion(request, response, null);
                  return false;
              }
              this.interceptorIndex = i;
          }
          return true;
      }
      

      攔截器方法回傳的是布林值,True 表示可以繼續執行, False 表示需要進行攔截,終止請求,

    4. 執行 HandlerAdapter 實體的 handle() 方法,其內部呼叫與之匹配的我們自己實作的 Controller 的方法,并回傳一個 ModelAndView 物件

      Controller 中對應的方法是真正處理請求的地方,呼叫業務層方法,業務層會跟持久層互動,持久層和資料庫互動,

    5. 執行 HandlerExecutionChain 實體的 applyPostHandle() 方法,其內部呼叫攔截器的 postHandle() 方法

      void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
          throws Exception {
      
          for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
              HandlerInterceptor interceptor = this.interceptorList.get(i);
              interceptor.postHandle(request, response, this.handler, mv);
          }
      }
      
    6. 執行 DispatcherServlet 實體的 processDispatchResult() 方法,進行視圖處理:

      1. 呼叫 DispatcherServlet 實體的 render() 方法

        1. 呼叫 DispatcherServlet 實體的 resolveViewName() 方法,回傳 View 的實體

          protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
                                         Locale locale, HttpServletRequest request) throws Exception {
          
              if (this.viewResolvers != null) {
                  for (ViewResolver viewResolver : this.viewResolvers) {
                      View view = viewResolver.resolveViewName(viewName, locale);
                      if (view != null) {
                          return view;
                      }
                  }
              }
              return null;
          }
          

          此處會呼叫視圖決議器的實體,視圖決議器使我們在組態檔中定義過的,功能其實就是拼接視圖名,包裝一個 View 物件回傳

          <!--視圖決議器:DispatcherServlet給他的ModelAndView-->
          <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
           <!--前綴-->
           <property name="prefix" value="/WEB-INF/jsp/"/>
           <!--后綴-->
           <property name="suffix" value=".jsp"/>
          </bean>
          
        2. 呼叫前面回傳的 View 實體的 render() 方法,回傳給客戶端瀏覽器

      2. 呼叫 HandlerExecutionChain 實體的 triggerAfterCompletion() 方法,該方法在視圖渲染后執行,這個方法的主要是用來處理控制器拋出的例外,

5. RESTful 風格

5.1 概念

RESTful 就是一個資源定位及資源操作的風格,不是標準也不是協議,只是一種風格,基于這個風格設計的軟體可以更簡潔,更有層次,更易于實作快取等機制,

傳統方式操作資源 :通過不同的引數來實作不同的效果!方法單一,post 和 get

  • http://127.0.0.1/item/queryItem.action?id=1 查詢,GET

  • http://127.0.0.1/item/saveItem.action 新增,POST

  • http://127.0.0.1/item/updateItem.action 更新,POST

  • http://127.0.0.1/item/deleteItem.action?id=1 洗掉,GET或POST

使用 RESTful 操作資源 :可以通過不同的請求方式來實作不同的效果!如下:請求地址一樣,但是功能可以不同!

  • http://127.0.0.1/item/1 查詢,GET
  • http://127.0.0.1/item 新增,POST
  • http://127.0.0.1/item 更新,PUT
  • http://127.0.0.1/item/1 洗掉,DELETE

5.2 RESTful 架構風格的特點

5.2.1 資源

所謂"資源",就是網路上的一個物體,或者說是網路上的一個具體資訊,它可以是一段文本、一張圖片、一首歌曲、一種服務,總之就是一個具體的實在,資源總要通過某種載體反應其內容,文本可以用 txt 格式表現,也可以用 HTML 格式、XML 格式表現,甚至可以采用二進制格式;圖片可以用 JPG 格式表現,也可以用 PNG 格式表現;JSON 是現在最常用的資源表示格式,

資源是以 json(或其他 Representation )為載體的、面向用戶的一組資料集,資源對資訊的表達傾向于概念模型中的資料:

  • 資源總是以某種 Representation 為載體顯示的,即序列化的資訊
  • 常用的 Representation 是 json(推薦)或者 xml(不推薦)等
  • Represntation 是 REST 架構的表現層

5.2.2 統一介面

RESTful 架構風格規定,資料的元操作,即 CRUD(Create,Retrieve,Update 和 Delete,即資料的增刪查改)操作,分別對應于 HTTP 方法:GET 用來獲取資源,POST 用來新建資源(也可以用于更新資源),PUT 用來更新資源,DELETE 用來洗掉資源,這樣就統一了資料操作的介面,僅通過 HTTP 方法,就可以完成對資料的所有增刪查改作業,即:

  • GET(SELECT):從服務器取出資源(一項或多項),
  • POST(CREATE):在服務器新建一個資源,
  • PUT(UPDATE):在服務器更新資源(客戶端提供完整資源資料),
  • PATCH(UPDATE):在服務器更新資源(客戶端提供需要修改的資源資料),
  • DELETE(DELETE):從服務器洗掉資源,

5.2.3 URI

可以用一個 URI(統一資源定位符)指向資源,即每個 URI 都對應一個特定的資源,要獲取這個資源,訪問它的 URI 就可以,因此 URI 就成了每一個資源的地址或識別符,

一般的,每個資源至少有一個 URI 與之對應,最典型的 URI 即 URL,

5.2.4 無狀態

所謂無狀態的,即所有的資源,都可以通過 URI 定位,而且這個定位與其他資源無關,也不會因為其他資源的變化而改變,有狀態和無狀態的區別,舉個簡單的例子說明一下,如查詢員工的工資,如果查詢工資是需要登錄系統,進入查詢工資的頁面,執行相關操作后,獲取工資的多少,則這種情況是有狀態的,因為查詢工資的每一步操作都依賴于前一步操作,只要前置操作不成功,后續操作就無法執行;如果輸入一個 url 即可得到指定員工的工資,則這種情況是無狀態的,因為獲取工資不依賴于其他資源或狀態,且這種情況下,員工工資是一個資源,由一個 url 與之對應,可以通過 HTTP 中的 GET 方法得到資源,這是典型的 RESTful 風格,

5.2.5 ROA、SOA、REST 與 RPC

ROA 即 Resource Oriented Architecture,RESTful 架構風格的服務是圍繞資源展開的,是典型的 ROA 架構(雖然“A”和“架構”存在重復,但說無妨),雖然 ROA 與 SOA 并不沖突,甚至把 ROA 看做 SOA 的一種也未嘗不可,但由于 RPC 也是 SOA,比較久遠一點點論文、博客或圖書也常把 SOA 與 RPC 混在一起討論,因此,RESTful 架構風格的服務通常被稱之為 ROA 架構,很少提及 SOA 架構,以便更加顯式的與 RPC 區分,

RPC 風格曾是 Web Service 的主流,最初是基于 XML-RPC 協議(一個遠程程序呼叫(remote procedure call,RPC)的分布式計算協議),后來漸漸被 SOAP 協議(簡單物件訪問協議(Simple Object Access Protocol))取代;RPC 風格的服務,不僅可以用 HTTP,還可以用 TCP 或其他通信協議,但 RPC 風格的服務,受開發服務采用語言的束縛比較大,如 .NET 框架中,開發 web service 的傳統方式是使用 WCF,基于 WCF 開發的服務即 RPC 風格的服務,使用該服務的客戶端通常要用 C# 來實作,如果使用 python 或其他語言,很難實作可以直接與服務通信客戶端;進入移動互聯網時代后,RPC 風格的服務很難在移動終端使用,而 RESTful 風格的服務,由于可以直接以 json 或 xml 為載體承載資料,以 HTTP 方法為統一介面完成資料操作,客戶端的開發不依賴于服務實作的技術,移動終端也可以輕松使用服務,這也加劇了 REST 取代 RPC 成為 web service 的主導,

5.3 認證機制

由于 RESTful 風格的服務是無狀態的,認證機制尤為重要,例如上文提到的員工工資,這應該是一個隱私資源,只有員工本人或其他少數有權限的人有資格看到,如果不通過權限認證機制對資源做一層限制,那么所有資源都以公開方式暴露出來,這是不合理的,也是很危險的,

認證機制解決的問題是,確定訪問資源的用戶是誰;權限機制解決的問題是,確定用戶是否被許可使用、修改、洗掉或創建資源,權限機制通常與服務的業務邏輯系結,因此權限機制需要在每個系統內部定制,而認證機制基本上是通用的,常用的認證機制包括 session auth(即通過用戶名密碼登錄),basic authtoken authOAuth,服務開發中常用的認證機制為后三者,

OAuth(開放授權)是一個開放的授權標準,允許用戶讓第三方應用訪問該用戶在某一web服務上存盤的私密的資源(如照片,視頻,聯系人串列),而無需將用戶名和密碼提供給第三方應用,

OAuth 允許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務提供者的資料,每一個令牌授權一個特定的第三方系統(例如,視頻編輯網站)在特定的時段(例如,接下來的 2 小時內)內訪問特定的資源(例如僅僅是某一相冊中的視頻),這樣,OAuth 讓用戶可以授權第三方網站訪問他們存盤在另外服務提供者的某些特定資訊,而非所有內容,

正是由于 OAuth 的嚴謹性和安全性,現在 OAuth 已成為 RESTful 架構風格中最常用的認證機制,和 RESTful 架構風格一起,成為企業級服務的標配,

5.4 簡單 RESTFul 請求

  1. 在新建一個類

    package com.ice.controller;
    
    import org.springframework.stereotype.Controller;
    
    @Controller
    public class RestFulController {
    }
    
  2. 在Spring MVC 中可以使用 @PathVariable 注解,讓方法引數的值對應系結到一個 URI 模板變數上

    package com.ice.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class RestFulController {
    
        @RequestMapping("/commit/{p1}/{p2}")
        public String index(@PathVariable int p1, @PathVariable int p2, Model model) {
            int result = p1+p2;
            //Spring MVC會自動實體化一個Model物件用于向視圖中傳值
            model.addAttribute("msg", "結果:"+result);
            //回傳視圖位置
            return "hello";
        }
        
    }
    
  3. 結果

在這里插入圖片描述

  1. 使用路徑變數的好處

    • 使路徑變得更加簡潔;

    • 獲得引數更加方便,框架會自動進行型別轉換,

    • 通過路徑變數的型別可以約束訪問引數,如果型別不一樣,則訪問不到對應的請求方法,如這里訪問是的路徑是 /commit/1/a,則路徑與方法不匹配,而不會是引數轉換失敗,

      在這里插入圖片描述

5.5 使用method屬性指定請求型別

用于約束請求的型別,可以收窄請求范圍,指定請求謂詞的型別如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等

  1. 增加一個方法

    @RequestMapping(value = "/hello", method = RequestMethod.POST)
    public String index2(Model model) {
        model.addAttribute("msg", "hello!");
        return "hello";
    }
    
  2. 我們使用瀏覽器地址欄進行訪問默認是Get請求,會報錯405:

在這里插入圖片描述

  1. 如果將POST修改為GET則正常了

    @RequestMapping(value="/hello", method = RequestMethod.GET)
    public String index2(Model model) {
        model.addAttribute("msg", "hello!");
        return "hello";
    }
    

    在這里插入圖片描述

所有的地址欄請求默認都會是 HTTP GET 型別的,

方法級別的注解變體有如下幾個:組合注解

@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping

@GetMapping 是一個組合注解,平時使用的會比較多!

它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一個快捷方式,

6. Spring MVC 轉發與重定向

@Controller
public class ResultSpringMVC2 {
   @RequestMapping("/rsm2/t1")
   public String test1(){
       //轉發
       return "test";
  }

   @RequestMapping("/rsm2/t2")
   public String test2(){
       //重定向
       return "redirect:/index.jsp";
       //return "redirect:hello.do"; //hello.do為另一個請求/
  }
}

7. 資料處理

7.1 處理提交資料

7.1.1 提交的域名稱和處理方法的引數名一致

提交資料:http://localhost:8080/test?name=ice

處理方法:

@RequestMapping("/test")
public String test(String name, Model model) {
    //Spring MVC會自動實體化一個Model物件用于向視圖中傳值
    model.addAttribute("msg", name);
    //回傳視圖位置
    return "hello";
}

7.1.2 提交的域名稱和處理方法的引數名不一致

提交資料:http://localhost:8080/test?username=ice

處理方法:

@RequestMapping("/test")
public String test(@RequestParam("username") String name, Model model) {
    //Spring MVC會自動實體化一個Model物件用于向視圖中傳值
    model.addAttribute("msg", name);
    //回傳視圖位置
    return "hello";
}

7.1.3 提交的是一個物件

要求提交的表單域和物件的屬性名一致 , 引數使用物件即可

  • 物體類

    package com.ice.pojo;
    
    import java.util.StringJoiner;
    
    
    public class User {
        private int id;
        private String name;
        private int age;
    
        public User() {
        }
    
        public User(int id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
    
        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 int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return new StringJoiner(", ", User.class.getSimpleName() + "[", "]")
                    .add("id=" + id)
                    .add("name='" + name + "'")
                    .add("age=" + age)
                    .toString();
        }
    }
    
  • 提交資料:http://localhost:8080/test?name=ice&id=1&age=18

  • 處理方法

    @RequestMapping("/test")
    public String test(User user, Model model) {
        //Spring MVC會自動實體化一個Model物件用于向視圖中傳值
        model.addAttribute("msg", user);
        //回傳視圖位置
        return "hello";
    }
    

說明:如果使用物件的話,前端傳遞的引數名和物件名必須一致,否則就是null,

7.2 資料顯示到前端

第一種 : 通過ModelAndView

我們前面一直都是如此,就不過多解釋

public class ControllerTest1 implements Controller {

   public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
       //回傳一個模型視圖物件
       ModelAndView mv = new ModelAndView();
       mv.addObject("msg","ControllerTest1");
       mv.setViewName("test");
       return mv;
  }
}

第二種 : 通過ModelMap

@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap model){
   //封裝要顯示到視圖中的資料
   //相當于req.setAttribute("name",name);
   model.addAttribute("name",name);
   System.out.println(name);
   return "hello";
}

第三種 : 通過Model

@RequestMapping("/ct2/hello")
public String hello(@RequestParam("username") String name, Model model){
   //封裝要顯示到視圖中的資料
   //相當于req.setAttribute("name",name);
   model.addAttribute("msg",name);
   System.out.println(name);
   return "test";
}

Model 只有寥寥幾個方法只適合用于儲存資料,簡化了新手對于Model物件的操作和理解;

ModelMap 繼承了 LinkedMap ,除了實作了自身的一些方法,同樣的繼承 LinkedMap 的方法和特性;

ModelAndView 可以在儲存資料的同時,可以進行設定回傳的邏輯視圖,進行控制展示層的跳轉,

8. 亂碼問題

不得不說,亂碼問題是在我們開發中十分常見的問題,也是讓我們程式猿比較頭大的問題!

以前亂碼問題通過過濾器解決 , 而SpringMVC給我們提供了一個過濾器 , 可以在web.xml中配置,修改了xml檔案需要重啟服務器!

<filter>
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

但是我們發現 , 有些極端情況下,這個過濾器對get的支持不好,

處理方法 :

  1. 修改tomcat組態檔 :設定編碼!

    <Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
              connectionTimeout="20000"
              redirectPort="8443" />
    
  2. 自定義過濾器

    import javax.servlet.*;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.Map;
    
    /**
    * 解決get和post請求 全部亂碼的過濾器
    */
    public class GenericEncodingFilter implements Filter {
    
       @Override
       public void destroy() {
      }
    
       @Override
       public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
           //處理response的字符編碼
           HttpServletResponse myResponse=(HttpServletResponse) response;
           myResponse.setContentType("text/html;charset=UTF-8");
    
           // 轉型為與協議相關物件
           HttpServletRequest httpServletRequest = (HttpServletRequest) request;
           // 對request包裝增強
           HttpServletRequest myrequest = new MyRequest(httpServletRequest);
           chain.doFilter(myrequest, response);
      }
    
       @Override
       public void init(FilterConfig filterConfig) throws ServletException {
      }
    
    }
    
    //自定義request物件,HttpServletRequest的包裝類
    class MyRequest extends HttpServletRequestWrapper {
    
       private HttpServletRequest request;
       //是否編碼的標記
       private boolean hasEncode;
       //定義一個可以傳入HttpServletRequest物件的建構式,以便對其進行裝飾
       public MyRequest(HttpServletRequest request) {
           super(request);// super必須寫
           this.request = request;
      }
    
       // 對需要增強方法 進行覆寫
       @Override
       public Map getParameterMap() {
           // 先獲得請求方式
           String method = request.getMethod();
           if (method.equalsIgnoreCase("post")) {
               // post請求
               try {
                   // 處理post亂碼
                   request.setCharacterEncoding("utf-8");
                   return request.getParameterMap();
              } catch (UnsupportedEncodingException e) {
                   e.printStackTrace();
              }
          } else if (method.equalsIgnoreCase("get")) {
               // get請求
               Map<String, String[]> parameterMap = request.getParameterMap();
               if (!hasEncode) { // 確保get手動編碼邏輯只運行一次
                   for (String parameterName : parameterMap.keySet()) {
                       String[] values = parameterMap.get(parameterName);
                       if (values != null) {
                           for (int i = 0; i < values.length; i++) {
                               try {
                                   // 處理get亂碼
                                   values[i] = new String(values[i]
                                          .getBytes("ISO-8859-1"), "utf-8");
                              } catch (UnsupportedEncodingException e) {
                                   e.printStackTrace();
                              }
                          }
                      }
                  }
                   hasEncode = true;
              }
               return parameterMap;
          }
           return super.getParameterMap();
      }
    
       //取一個值
       @Override
       public String getParameter(String name) {
           Map<String, String[]> parameterMap = getParameterMap();
           String[] values = parameterMap.get(name);
           if (values == null) {
               return null;
          }
           return values[0]; // 取回引數的第一個值
      }
    
       //取所有值
       @Override
       public String[] getParameterValues(String name) {
           Map<String, String[]> parameterMap = getParameterMap();
           String[] values = parameterMap.get(name);
           return values;
      }
    }
    

    這個也是在網上找的一些大神寫的,一般情況下,SpringMVC默認的亂碼處理就已經能夠很好的解決了!

    然后在web.xml中配置這個過濾器即可!

    亂碼問題,需要平時多注意,在盡可能能設定編碼的地方,都設定為統一編碼 UTF-8!

9. 攔截器

9.1 概述

Spring MVC 的處理器攔截器類似于 Servlet 開發中的過濾器 Filter,用于對處理器進行預處理和后處理,開發者可以自己定義一些攔截器來實作特定的功能,

過濾器與攔截器的區別:攔截器是AOP思想的具體應用,

過濾器

  • servlet 規范中的一部分,任何 java web工程都可以使用
  • url-pattern 中配置了 /* 之后,可以對所有要訪問的資源進行攔截

攔截器

  • 攔截器是 SpringMVC 框架自己的,只有使用了 Spring MVC 框架的工程才能使用
  • 攔截器只會攔截訪問的控制器方法, 如果訪問的是 jsp/html/css/image/js 是不會進行攔截的

9.2 自定義攔截器

想要自定義攔截器,必須實作 HandlerInterceptor 介面,

  1. 新建一個 project, 添加web支持

  2. 配置 web.xml 和 applicationContext.xml 檔案

  3. 撰寫一個攔截器

    package com.ice.interceptor;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("====處理前===");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("====處理后===");
        }
    }
    
  4. 在 spring mvc 的組態檔中配置攔截器

    <?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 http://www.springframework.org/schema/context/spring-context.xsd
                               http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
        <!-- 自動掃描包,讓指定包下的注解生效,由IOC容器統一管理 -->
        <context:component-scan base-package="com.ice.controller"/>
        <!-- 讓Spring MVC不處理靜態資源 -->
        <mvc:default-servlet-handler/>
        <!-- 支持mvc注解驅動 -->
        <mvc:annotation-driven/>
    
        <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/**"/>
                <bean class="com.ice.interceptor.MyInterceptor"/>
            </mvc:interceptor>
        </mvc:interceptors>
    
        <!-- 視圖決議器 -->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
              id="internalResourceViewResolver">
            <!-- 前綴 -->
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <!-- 后綴 -->
            <property name="suffix" value=".jsp"/>
        </bean>
    
    </beans>
    
  5. 撰寫一個Controller,接收請求

    package com.ice.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class TestController {
    
        @GetMapping("/test")
        public String test() {
            System.out.println("TestController ==》 test() 執行了");
            return "OK";
        }
    }
    
  6. 啟動 Tomcat 測驗

在這里插入圖片描述

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/257077.html

標籤:其他

上一篇:JavaWeb - 我們的開發規范(VO、DTO、BO、PO、DO、POJO)

下一篇:電子書下載|2020 年云原生年貨小紅書來啦!

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more