SpringMvc 純注解搭建和 Request 小結


SpringMvc 是一種底層基於 Servlet 實現 MVC 模型的輕量級 Web 開發框架,是一種側重於表現層的開發技術。

SpringMvc 使用起來比 Servlet 要方便很多,性能也很不錯,常用於小型項目的快速搭建和開發。本篇博客不會介紹有關 MVC 的理論知識,主要側重於代碼實踐,采用純注解的方式快速搭建 SpringMvc 工程,並展示常用的接收請求參數的方式。在本篇博客的最后會提供 Demo 的源代碼。

有關 SpringMvc 的詳細使用可參考官網:
https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc


一、搭建工程

新建一個 maven 項目,導入相關 jar 包,我所導入的 jar 包都是最新的,內容如下:

有關具體的 jar 包地址,可以在 https://mvnrepository.com 上進行查詢。

<dependencies>
    <!--導入 servlet 相關的 jar 包-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>
    
    <!--導入 Spring 核心 jar 包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.18</version>
    </dependency>
    <!--導入 SpringMvc 的 jar 包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.18</version>
    </dependency>
</dependencies>

配置好引用的 jar 包后,打開右側的 Maven 窗口,刷新一下,這樣 Maven 會自動下載所需的 jar 包文件。

搭建好的項目工程整體目錄比較簡單,具體如下圖所示:

image

項目工程結構簡單介紹:

com.jobs.config 包下存儲的是 SpringMvc 的配置文件和 Servlet 的初始化文件
com.jobs.controller 包下存儲的是用於提供 http 請求的類
com.jobs.domain 包下存儲的是 JavaBean 實體類

web 目錄下放置的是網站文件,其中 statics 目錄下存放是靜態資源文件


二、SpringMvc 配置相關

com.jobs.config 下的 SpringMvcConfig 類是 SpringMvc 的配置類,具體內容如下:

package com.jobs.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@Configuration
@ComponentScan("com.jobs")
//啟用 mvc 功能,配置了該注解之后,SpringMvc 攔截器放行相關資源的設置,才會生效
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {

    //配置 SpringMvc 攔截器放行的資源類型
    /*@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/statics/**").addResourceLocations("/statics/");
        //registry.addResourceHandler("/statics/css/**").addResourceLocations("/statics/css/");
        //registry.addResourceHandler("/statics/img/**").addResourceLocations("/statics/img/");
        //registry.addResourceHandler("/statics/js/**").addResourceLocations("/statics/js/");
    }*/

    //配置 SpringMvc 連接器放行常用資源的格式(圖片,js,css)
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    //注解配置 SpringMvc 返回配置的字符串所表示的頁面,從哪些去找
    //可以注釋掉下面的方法,這樣需要在 SpringMvc 方法返回時,指定全局路徑的頁面地址
    //這里配置的是:根據 SpringMvc 方法返回的字符串,到 /WEB-INF/pages/ 下找對應名稱的 jsp 頁面
    @Bean
    public InternalResourceViewResolver getViewResolver(){
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/pages/");
        viewResolver.setSuffix(".jsp");
        //如果頁面需要使用JSTL標簽庫的話
        //viewResolver.setViewClass(JstlView.class);
        return viewResolver;
    }
}

這里需要注意以下幾項:

  • 使用注解 @ComponentScan 中的 includeFilters 指定 SpringMvc 只掃描裝載帶有 @Controller 注解的類,其它的注解不需要給 SpringMvc 掃描,其它的注解全部交給 Spring 來掃描裝載。
  • 必須在 SpringMvc 的配置類上添加 @EnableWebMvc 注解,這樣才能夠有機會訪問到靜態資源(圖片、css、js)。
  • 可以重寫 configureDefaultServletHandling 方法,只需要一句代碼 configurer.enable() 即可讓 SpringMvc 攔截器放行靜態資源的訪問限制。

SpringMvc 技術底層是基於 Servlet 實現的,因此必須讓 Servlet 裝載才能實現,我們編寫 ServletInitConfig 類初始化 Servlet 容器,裝載 SpringMvc 的配置,具體內容如下:

package com.jobs.config;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.EnumSet;

public class ServletInitConfig extends AbstractDispatcherServletInitializer {

    //初始化 Servlet 容器,加載 SpringMvc 配置類
    //創建 web 專用的 Spring 容器對象:WebApplicationContext
    @Override
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext cwa = new AnnotationConfigWebApplicationContext();
        //裝載 SpringMvc 的配置
        cwa.register(SpringMvcConfig.class);
        return cwa;
    }

    //配置 SpringMvc 的 DispatcherServlet 攔截地址,攔截所有請求
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }

    //在servlet容器啟動時進行配置統一字符編碼,防止接收到的中文參數值是亂碼
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        //這行代碼不能省略
        super.onStartup(servletContext);

        //設置【獲取到的請求】的統一字符編碼過濾器,
        //無論是【請求、轉發、包含】統一使用 UTF-8 編碼
        CharacterEncodingFilter cef = new CharacterEncodingFilter();
        cef.setEncoding("UTF-8");
        //注意:這里的過濾器名稱必須是 characterEncodingFilter
        FilterRegistration.Dynamic registration =
            servletContext.addFilter("characterEncodingFilter", cef);
        registration.addMappingForUrlPatterns(
            EnumSet.of(DispatcherType.REQUEST,
                DispatcherType.FORWARD, DispatcherType.INCLUDE), false, "/*");
    }
}

經過上面兩個類的處理,SpringMvc 純注解方式已經配置完畢,下面就可以使用 SpringMvc 技術處理請求了。


三、驗證搭建成果

我們編寫 ReqController1 類來驗證 SpringMvc 搭建成果,具體內容如下:

package com.jobs.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

//@RequestMapping 注解可以在類上使用,也可以在類中具體的方法上使用
@RequestMapping("/req1")
@Controller
public class ReqController1 {

    //使用配置的前綴和后綴
    @RequestMapping("/test1")
    public String SpringMvcTest1() {
        System.out.println("SpringMvc 搭建成功...默認使用所配置的前綴和后綴");

        //由於在 SpringMvcConfig 類中的 getViewResolver 方法,配置了前綴和后綴
        //因此這里如果返回字符串的話,默認會到 /WEB-INF/pages/ 下找對應名稱的 jsp 頁面
        //由於這里返回字符串 success,因此直接找 /WEB-INF/pages/success.jsp 頁面
        return "success";
    }

    //臨時不想使用所配置的前綴和后綴
    @RequestMapping("test2")
    public String SpringMvcTest2() {
        System.out.println("SpringMvc 如果不想使用所配置的前綴和后綴,可以使用 forward 或 redirect");

        //當使用了 forward 或 redirect 時,將不使用所配置的前綴和后綴
        return "forward:/ok.html";
        //return "redirect:/ok.html";
    }

    //訪問靜態資源
    @RequestMapping(value = "test3")
    public String SpringMvcTest3() {
        System.out.println("SpringMvc 查看靜態資源");

        //由於在 SpringMvcConfig 類中重寫了 configureDefaultServletHandling 方法,
        //啟用了常用的靜態資源訪問,所以 SpringMvc 不會攔截靜態資源的訪問
        //在 picture.jsp 頁面,可以看到 css 樣式效果,圖片展示,以及外部 js 引用后可以運行
        return "picture";
    }
}

上面用到的靜態資源內容如下:

test.css 的內容為:

h1{
    color: coral;
}

test.js 的內容為:

function testalert() {
    alert('努力學習,天天向上!!!');
}

所用到的頁面內容如下:

success.jsp 頁面代碼為:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>請求成功</title>
    <link rel="stylesheet" href="${pageContext.request.contextPath}/statics/css/test.css">
</head>
<body>
    <h1>這里是 jsp 動態頁面:success.jsp</h1>
    <h1>請求成功,請查看控制台上打印的結果...</h1>
</body>
</html>

picture.jsp 頁面代碼為:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <link rel="stylesheet" href="${pageContext.request.contextPath}/statics/css/test.css">
</head>
<body>
    <h1>這里是 picture.jsp 展示靜態資源(圖片,css,js)的訪問:</h1>
    <img src="${pageContext.request.contextPath}/statics/img/study.jpg"/>
    <input type="button" onclick="testalert()" value="點擊我,運行js彈出框"/>

    <!--建議把 js 文件放在網頁的最下面,提高網頁的打開速度-->
    <script src="${pageContext.request.contextPath}/statics/js/test.js"></script>
</body>
</html>

ok.html 靜態頁面的代碼為:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>請求成功</title>
    <link rel="stylesheet" href="/statics/css/test.css">
</head>
<body>
    <h1>這里是靜態頁面:ok.html</h1>
    <h1>請求成功,請查看控制台上打印的結果...</h1>
</body>
</html>

四、請求參數的接收

首先列出 Employee 實體類,因為下面的代碼會演示使用實體類作為接收參數,來接收請求參數中的值,然后編寫 ReqController2 類,來演示在實際開發中,常用的一些請求參數的接收方式,具體細節如下:

package com.jobs.domain;

import java.util.List;

public class Employee {

    //姓名
    private String name;
    //年齡
    private Integer age;
    //愛好
    private List<String> hobby;

    //這里省略了各個字段的 get 和 set 方法...

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", hobby=" + hobby +
                '}';
    }
}
package com.jobs.controller;

import com.jobs.domain.Employee;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

//@RequestMapping 注解可以在類上使用,也可以在類中具體的方法上使用
//@RequestMapping("req2")
@Controller
public class ReqController2 {

    //請求參數與接收參數,名稱必須一致,如果參數缺少,則參數取類型默認值
    //http://localhost:8080/request1?name=jobs
    //http://localhost:8080/request1?name=jobs&age=33
    @RequestMapping("/request1")
    public String request1(String name, Integer age) {
        String result = "name=" + name + ",age=" + age;
        System.out.println(result);
        return "success";
    }

    //設置請求參數的名稱,以及是否為必須提供的參數,以及設置參數的默認值
    //http://localhost:8080/request2 報錯,沒有提供必填參數 userName
    //http://localhost:8080/request2?name=jobs
    //http://localhost:8080/request2?name=jobs&age=33
    @RequestMapping("/request2")
    public String request2(
            @RequestParam(value = "userName", required = true) String name,
            @RequestParam(value = "userAge", defaultValue = "30") Integer age) {
        String result = "name=" + name + ",age=" + age;
        System.out.println(result);
        return "success";
    }

    //請求參數名稱,與接收參數的 JavaBean 類的字段名稱相同的話,
    //則 SpringMvc 會根據請求參數自動給 JavaBean 實例化的對象屬性賦值
    //http://localhost:8080/request3?name=jobs
    //http://localhost:8080/request3?name=jobs&age=33
    @RequestMapping("/request3")
    public String request3(Employee emp) {
        String result = "name=" + emp.getName() + ",age=" + emp.getAge();
        System.out.println(result);
        return "success";
    }

    //如果接收參數中,普通參數名稱 與 JavaBean 類的字段名稱相同的話,則都會進行賦值
    //http://localhost:8080/request4?name=jobs&age=33
    @RequestMapping("/request4")
    public String request4(Employee emp, String name, Integer age) {
        StringBuilder sb = new StringBuilder();
        sb.append("使用 JavaBean 類作為參數,獲取的結果:");
        sb.append("name=" + emp.getName() + ",age=" + emp.getAge());
        sb.append("\r\n");
        sb.append("使用普通參數獲取的結果:");
        sb.append("name=" + name + ",age=" + age);

        String result = sb.toString();
        System.out.println(result);
        return "success";
    }

    //使用數組作為參數,接收傳入的數組數據
    //http://localhost:8080/request5?hobby=唱歌&hobby=跳舞&hobby=打游戲
    @RequestMapping("/request5")
    public String request5(String[] hobby) {
        if (hobby != null && hobby.length > 0) {
            for (String h : hobby) {
                System.out.println(h);
            }
        } else {
            System.out.println("未獲取到所傳入的 hobby 數據");
        }

        return "success";
    }

    //使用集合作為參數,接收傳入的數組數據,無法直接獲取數組數據
    //必須要使用 @RequestParam 注解將請求參數與接收參數進行名稱映射
    //http://localhost:8080/request6?hobby=唱歌&hobby=跳舞&hobby=打游戲
    @RequestMapping("/request6")
    public String request6(
            @RequestParam(value = "hobby") List<String> hobbylist) {
        if (hobbylist != null && hobbylist.size() > 0) {
            for (String hobby : hobbylist) {
                System.out.println(hobby);
            }
        } else {
            System.out.println("未獲取到所傳入的 hobby 數據");
        }

        return "success";
    }

    //使用 JavaBean 類作為接收參數,接收數組數據
    //http://localhost:8080/request7?hobby=唱歌&hobby=跳舞&hobby=打游戲
    @RequestMapping("/request7")
    public String request7(Employee emp) {
        List<String> hobbylist = emp.getHobby();
        if (hobbylist != null && hobbylist.size() > 0) {
            for (String hobby : hobbylist) {
                System.out.println(hobby);
            }
        } else {
            System.out.println("未獲取到所傳入的 hobby 數據");
        }

        return "success";
    }

    //發來的請求數據,如果是日期類型,如果想直接使用日期類型的參數進行接收的話,
    //可以根據傳入數據的日期格式,明確指定好接收數據的對應格式,就可以接收到具體的日期數據
    //http://localhost:8080/request8?date=2022-01-21 15:20:30
    @RequestMapping("/request8")
    public String request8(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH時mm分ss秒");
        String dateString = sdf.format(date);
        System.out.println(dateString);

        return "success";
    }

    //可以接收提交過來的 body 數據,必須使用 Post 請求方式
    //默認情況下,各種請求方式都支持,可以通過 method 指定允許的請求方式
    //這里可以使用 PostMan 來請求該接口,必須使用 Post 請求方式從 body 中獲取數據
    //http://localhost:8080/request9
    @RequestMapping(value = "/request9", method = RequestMethod.POST)
    public String request9(@RequestBody String json) {
        System.out.println(json);
        return "success";
    }
}

上面的請求方式代碼中,最后一個請求方法,從 body 中獲取數據,需要采用 Post 請求才可以。這里可以使用 PostMan 工具進行測試,在 PostMan 工具中可以 Post 發送各種類型的數據,這里僅僅以 Post 發送 Json 數據為例,因為在實際開發中,向服務器發送 Json 格式的數據比較常用,使用 PostMan 工具請求最后一個接口的細節如下所示:

image

在 IDEA 工具的控制台上打印出 Post 請求發送過來的數據:

image



到此為止,SpringMvc 采用純注解方式快速搭建已經介紹完畢。在 SpringMvc 的純注解配置中實現了監控所有請求,並忽略和放行常見靜態資源的請求,通過配置前綴和后綴,實現通過返回的字符串自動查找對應路徑下的 jsp 頁面。最后列出了常用的接收傳入的參數值的幾種方式。

本篇博客的 demo 源代碼下載地址為:https://files.cnblogs.com/files/blogs/699532/SpringMVC_Request.zip




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM