22-06-17 西安 ssm-springmvc(01) SpringMVC环境搭建及入门案例、@RequestMapping、2种暗黑风格、获取请求参数

MVC思想

MVC是一种软件架构的思想

M:Model,模型层,指工程中的JavaBean,作用是处理数据

V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据

C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器


SpringMVC

SpringMVC是Spring的一个后续产品,是Spring的一个子项目。

SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案,(表述层=页面+控制层)


SpringMVC的特点:
1.Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
2.基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理

比如:Strust1封装了servlet,Strust2封装过滤器,都是apache产品
Strust1和Strust2俩个根本不是同一个产品。


SpringMVC入门案例

框架本质:jar包+配置文件

1.创建maven的web工程,并配置好tomcat,方式如下:

22-06-02 javaweb(13) 西安 maven、项目构建和依赖管理_£小羽毛的博客-CSDN博客

2.引入依赖

<dependencies>
    <!-- SpringMVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.1</version>
    </dependency>

    <!-- 日志 -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>

    <!-- ServletAPI -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>

    <!-- Spring5和Thymeleaf整合包 -->
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
        <version>3.0.12.RELEASE</version>
    </dependency>
</dependencies>

3.web.xml注册SpringMVC的前端控制器DispatcherServlet

DispatcherServlet是SpringMVC所提供的前端控制器,对浏览器发送的请求统一进行处理

    <!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
    <servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <!--
            设置springMVC的核心控制器所能处理的请求的请求路径
            /所匹配的请求可以是/login或.html或.js或.css方式的请求路径
            但是/不能匹配.jsp请求路径的请求
        -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

问题1: <url-pattern>/</url-pattern>,  这里为什么不是"/*"  ?

 /不包括.jsp     /* 包括.jsp的访问。

写/,jsp被JspServlet处理,其他请求DispatcherServlet处理,合情合理

JspServlet:处理访问jsp的请求,会把jsp翻译成所对应的servlet 

问题2:在下面这个web.xml中有一个配置,DefaultServlet用来处理静态资源,它的 url-pattern 配置也是“/”

    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>  
   <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

这时候冲突了就近原则,

后面会再去解决处理静态资源的问题。

4.WEB-INF下创建springMVC-servlet.xml

为什么是这个名字呢?
固定位置,固定名称。位置是WEB-INF下,名称是 "<servlet-name>的值"-servlet.xml

springmvc配置文件在DispatcherServlet初始化时加载,获取ioc容器

springMVC-servlet.xml文件内容是:

扫描控制层组件:component-scan
配置Thymeleaf视图解析器,解析Thymeleaf视图。

<?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"
       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">
    <!-- 自动扫描包 -->
    <context:component-scan base-package="com.atguigu.controller"/>

    <!-- 配置Thymeleaf视图解析器 -->
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/>
        <property name="characterEncoding" value="UTF-8"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">

                        <!-- 视图前缀 -->
                        <property name="prefix" value="/WEB-INF/templates/"/>

                        <!-- 视图后缀 -->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8" />
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</beans>

5.创建com.atguigu.controller.HelloController

标识@Controller,SpringMVC才能够识别控制器的存在

@Controller
public class HelloController {
    @RequestMapping("/")
    public String index() {
        //设置逻辑视图
        return "index";
    }

    @RequestMapping("/hello")
    public String HelloWorld() {
        return "success";
    }
}

6.创建templates目录,index.html移进到该目录,之所以是templates,因为我们在springMVC-servlet.xml中的视图前缀的配置是这样的!

 index.html内容如下: 

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>index.html</h1>
    <a th:href="@{/hello}">hello</a>
</body>
</html>

success.html内容如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   <h1>success</h1>
</body>
</html>

启动项目后,自动跳转到首页

 点击超链接"hello",跳转到如下页面 


来,分析一波:

核心:将浏览器发送的请求和控制器方法所标识的注解@RequestMapping进行匹配

    @RequestMapping("/hello")
    public String HelloWorld() {
        return "success";
    }

若匹配成功,@RequestMapping注解所标识的方法就是处理请求的方法
在控制器方法中处理请求之后,需要返回一个字符串,该字符串就是逻辑视图
该视图会被配置文件中视图解析器解析,拼接前缀和后缀,结果Thymeleaf渲染响应浏览器

web.xml优化配置:

问题1:为什么第一次访问那么慢?,因为做的事实在太多了。springmvc的配置文件在DispatcherServlet初始化时加载

解决办法:将servlet的初始化时间提前到服务器启动时

<load-on-startup>1</load-on-startup>

问题2:我们的配置文件都在resources下,怎么把springmvc的配置文件也放在resources下?

解决办法:设置springmvc配置文件自定义的位置和名称,注意标签的设置顺序

    <!-- 配置SpringMVC的前端控制器,对浏览器发送的请求统一进行处理 -->
    <servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 通过初始化参数指定SpringMVC配置文件的位置和名称 -->
        <init-param>
            <!-- contextConfigLocation为固定值 -->
            <param-name>contextConfigLocation</param-name>
            <!-- 使用classpath:表示从类路径查找配置文件,例如maven工程中的src/main/resources -->
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>
        <!-- 
             作为框架的核心组件,在启动过程中有大量的初始化操作要做
            而这些操作放在第一次请求时才执行会严重影响访问速度
            因此需要通过此标签将启动控制DispatcherServlet的初始化时间提前到服务器启动时
        -->
        <load-on-startup>1</load-on-startup>
    </servlet>


 @RequestMapping注解

1.@RequestMapping作用:处理请求和控制器方法之间的映射关系

若请求的信息和注解所配置的信息能够匹配成功,那么注解所标识的方法就是处理该请求的方法

2、@RequestMapping所标识的位置

  标识在类上:设置所匹配请求的初始信息
  标识在方法上:设置所匹配请求的具体信息

先看一种情况,俩个Controller处理的请求就一样,俩个@RequestMapping("/hello"),这种情况就很常见,怎么区分呢?

@Controller
public class RequestMappingController {
    @RequestMapping("/hello")
    public String HelloWorld() {
        return "success";
    }
}


@Controller
public class HelloController {
    @RequestMapping("/hello")
    public String HelloWorld() {
        return "success";
    }
}

启动报错:

 我们在其中一个controller上加一个@RequestMapping就好了。

标识在类上:匹配的请求的初始信息
方法:具体信息

@Controller
@RequestMapping("/test")
public class RequestMappingController {
    @RequestMapping("/hello")
    public String HelloWorld() {
        return "success";
    }
}

这样以后再去访问就得加test了 


@RequestMapping属性

设置的@RequestMapping属性越多,匹配的请求越精确

1、@RequestMapping注解的value属性

通过请求路径将请求和控制器方法创建映射关系
 * value属性是字符串数组类型,浏览器发送的请求的请求路径和数组中的任何一个路径匹配成功,就可以通过该方法处理请求, 即浏览器发送的多个请求都可以被同一个控制器方法处理
 * 若请求的请求路径和控制器中任何一个@RequestMapping注解的value属性都不匹配,此时页面显示404

    @RequestMapping(value = {"/hello", "/abc"})
    public String HelloWorld() {
        return "success";
    }

2、@RequestMapping注解method属性

在value属性匹配请求路径的基础上,再通过请求方式去匹配

 *  method属性是一个RequestMethod类型的数组,RequestMethod是枚举类
 * 若当前请求的请求路径匹配成功,但是请求的请求方式不是@RequestMapping所支持的请求方式则抛出异常405,Request method "XXX" not supported(请求方式不被允许)

public enum RequestMethod {

	GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE

}
    @RequestMapping(value = {"/hello", "/abc"},method = RequestMethod.GET)
    public String HelloWorld() {
        return "success";
    }

@RequestMapping派生注解:

  • 处理get请求的映射-->@GetMapping
  • 处理post请求的映射-->@PostMapping

3、@RequestMapping注解的params属性

params属性通过请求的请求参数匹配请求映射

params属性要求所匹配的请求必须携带或者不携带某些请求参数

params属性是一个字符串类型的数组(数组里面的表达式必须都匹配)

params属性的值可以是四种表达式:

 "param":表示所匹配请求必须携带param请求参数
 "!param":表示所匹配请求不能携带param请求参数
 "param=value":表示所匹配请求必须携带param请求参数,且值必须为value
 "param!=value":表示所匹配请求携带param请求参数时(不是必须携带),值不能为value。

 * 若当前请求的其他属性能够匹配成功,但是params匹配不成功
 * 页面报错400 - Parameter conditions "username" not met for actual request parameters

如下写法,表示请求参数中必须有username请求参数,可以有password,但是不能为123456

    @RequestMapping(value = "/hello",params = {"username","password!=123456"})
    public String HelloWorld() {
        return "success";
    }


 4、@RequestMapping注解的headers属性

通过请求的请求头信息匹配请求映射
headers属性要求所匹配的请求必须携带或者不携带某些请求头信息

headers属性是一个字符串类型的数组
 * 该属性的用法和params一样
 * 若当前请求的其他属性能够匹配成功,但是headers匹配不成功,页面报错404

四种表达式

"header":要求请求映射所匹配的请求必须携带header请求头信息

"!header":要求请求映射所匹配的请求必须不能携带header请求头信息

"header=value":要求请求映射所匹配的请求必须携带header请求头信息且header=value

"header!=value":要求请求映射所匹配的请求携带header请求头信息且是header!=value

    @RequestMapping(value = "/hello",headers={"referer"})
    public String HelloWorld() {
        return "success";
    }

SpringMVC支持的2种暗黑风格

1、@RequestMapping支持ant风格的路径

 在@RequestMapping所设置value属性中,可以使用ant风格的特殊符号
 ?:表示任意的单个字符(不包括?和/)
 *:表示任意的0个或多个字符(里面不能包含?和/)
 **:表示任意层数的任意目录
 注意:使用**时,必须写在双//中,且前后不能有其他内容,否则会被当做两个单个的*被解析

    @RequestMapping("/a?a/ant")
    public String testAnt(){
        return "success";
    }

?:表示任意的单个字符(不包括?和/)

    @RequestMapping("/**/ant")
    public String testAnt(){
        return "success";
    }

("/**/ant") 表示任意层数的任意目录


2、SpringMVC支持路径中的占位符

是新的传输请求参数的方式,把请求参数拼接在路径中。

 可以在@RequestMapping的value属性匹配路径时,通过{}占位符的方式表示该请求参数
 在控制器方法中,可以通过@PathVariable注解将占位符的值和控制器方法的参数进行绑定

@RequestMapping("/path/{username}/{password}")
public String testPath(@PathVariable("username") String username, @PathVariable("password") String password){
    return "username:"+username+"===="+"password:"+password;
}

额外扩展,这么写也可以

 @RequestMapping("{id}.html")
 public String queryById(@PathVariable("id") String id){
     return "query:id="+id ;
 }


SpringMVC获取请求参数

1、用servletAPI获取请求参数

HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象

    @RequestMapping("/servletAPI")
    public String getParamByServletAPI(HttpServletRequest request){
        HttpSession session = request.getSession();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println("username:"+username+",password:"+password);
        return "success";
    }


2、控制器方法的形参获取请求参数

控制器方法的形参要和请求参数名要保持一致

    @RequestMapping("/getParam")
    public String getParam(String username, String password){
        System.out.println("username:"+username+",password:"+password);
        return "success";
    }

特殊情况:
控制器方法的形参要和请求参数名不一致。

@RequestParam 设置请求参数和控制器方法形参的映射关系

value:设置要和形参绑定的请求参数的参数名
required:是否必须携带value所指定的请求参数,默认值为true表示必须携带该请求参数
defaultValue:若当前value所指定请求参数为传输,则为绑定的形参赋值默认值,此时和required为true或false无关,有了defaultValue,required形同虚设!

    @RequestMapping("/param")
    public String getParam(@RequestParam(value = "name", required = true,
            defaultValue = "syl") String username, String password)
    {
        System.out.println("username:"+username+",password:"+password);
        return "success";
    }

@RequestHeader("请求头的键")

@RequestHeader注解将请求报文中请求头信息和控制器方法的形参进行绑定,用法和@RequestParam一样

    @RequestMapping("/header")
    public String testHeader(@RequestHeader(value = "referer") String referer){
        System.out.println(referer);
        return "success";
    }

@CookieValue("cookie的键")

@CookieValue注解将cookie数据和控制器方法的形参进行绑定,用法和@RequestParam一样

    //把键为JSESSIONID的cookie的值赋值给JSESSIONID 
    @RequestMapping("/cookie")
    public String testCookie(@CookieValue("JSESSIONID") String JSESSIONID){
        System.out.println(JSESSIONID);
        return "success";
    }

3、通过POJO获取请求参数。(用的最多)

针对要获取的请求参数有多个。但是要保证一致:请求参数的参数名和实体类中的属性名一致

此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参数就会为此属性赋值

    @RequestMapping("/pojo")
    public String getParamByPOJO(User user){
        System.out.println(user);
        return "success";
    }

user不可能为空,springmvc一定会创建User的对象,再解析接收请求参数


4、特殊情况,同名的请求参数

比如爱好

<form th:action="@{/test/pojo}" method="post">
    爱好:<input type="checkbox" name="hobby" value="A">A
    <input type="checkbox" name="hobby" value="B">B
    <input type="checkbox" name="hobby" value="C">C<br>
    <input type="submit" value="添加">
</form>

 方式一:通过字符串类型的数组获取,数组中是每个请求参数的值,[A,B,C]

    @RequestMapping("/pojo")
    public String getParamByPOJO(String[] hobby){
        System.out.println(Arrays.toString(hobby));
        return "success";
    }

方式二:通过字符串类型的形参获取,获取的结果为每个请求参数的值中间使用逗号拼接的结果,A,B,C

    @RequestMapping("/pojo")
    public String getParamByPOJO(String hobby){
        System.out.println(hobby);
        return "success";
    }


解决请求参数的乱码问题

CharacterEncodingFilter编码过滤器是spring提供给的,不是springMVC,不需要我们自己写

注意:

get请求不会出现乱码。post请求出现乱码。

SpringMVC中处理编码的过滤器一定要配置到其他过滤器之前,否则无效

<!--配置springMVC的编码过滤器-->
<filter>
    <filter-name>CharacterEncodingFilter</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>
    <init-param>
        <param-name>forceResponseEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值