SpringMVC配置

作者: 小杨小杨神采飞杨 | 来源:发表于2020-04-24 17:36 被阅读0次

    第一个MVC项目-HelloWorld

    基本原理:

    引用西部开源秦疆老师的图
    1、首先确认目录结构
    确认目录结构
    2、编写web.xml,主要是配置DispatcherServlet
    web.xml
    3、配置SpringMVC-servlet.xml
    SpringMVC-servlet.xml
    4、配置解析类
    解析类
    之后用户访问解析类内配置的名称,springmvc会自动调用在web.xml中配置的DispatcherServlet,DispatcherServlet首先会调用视图解析器根据设置的头尾拼接出完整资源名称,之后根据该名称查找对应的已注册的bean,找到后访问指定资源进行跳转

    注意:若代码没出错依旧无法运行,检查idea配置问题
    点击右上角


    配置

    查看当前web项目下是否有对应的lib包,若没有手动创建并导包


    配置问题

    使用注解配置

    配置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">
    
        <servlet>
            <servlet-name>SpringMVC</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <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>
        <servlet-mapping>
            <servlet-name>SpringMVC</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
        <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>
        </filter>
        <filter-mapping>
            <filter-name>CharacterEncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    

    配置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"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/mvc
            https://www.springframework.org/schema/mvc/spring-mvc.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd">
    
        <!--扫描指定包-->
        <context:component-scan base-package="cn.yzx.controller"/>
        <!--不处理静态资源-->
        <mvc:default-servlet-handler/>
        <!--
        开启支持mvc注解驱动,要想使@RequestMappering注解生效,需要开启
        处理器映射
        <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
        处理器适配器
        <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
        <mvc:annotation-driven/>自动注入了以上两个实例
        -->
        <mvc:annotation-driven/>
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <property name="suffix" value=".jsp"/>
        </bean>
    </beans>
    

    以上两个配置是死的,无序过多改动
    接下来就很简单了,随意的创建一个类,随意的创建一个方法,使用两个注解完成所有操作

    @Controller
    public class helloController {
        @RequestMapping("hello")
        public String hello(Model model) {
            model.addAttribute("msg","你好世界!!!"); //使用model共享数据
            return "hello"; //在视图解析器配置了前置后置,所以这里直接返回资源的名称即可
        }
    }
    

    补充:

    1. @Controller:
      就是将bean注册到ioc容器中的效果,但是@Controller稍微特殊一点,可以让容器知道他是一个Controller层的类

    2. @RequestMapping:

    • 标注在方法上,是告诉SpringMVC,这个方法用于处理什么请求,/是可以省略的,默认也是从当前项目开始寻找,加上比较好
    • 标注在类上,等于为WEB应用设置了一个根目录,下边的所有资源访问都要带上这一级目录名称例如标注在类上为"/haha",那么访问这个通过这个类下的所有方法访问资源都要带上/haha,访问hello就是/haha/hello以此类推
      标注在类上
      测试结果
      可见效果正是给该类下的资源添加了根路径信息
    1. @RequestMapping的其他属性;
      method:限定请求方式


      method

    params:设置请求参数信息,支持简单的表达式

    params = {"username"} //请求必须带有名为username的参数
    params = {"!username"} //请求不能带有名为username的参数
    params = {"username=123"} //请求必须带有名为username的参数且参数值必须为123
    params = {"username!=123"} //请求若带有名为username的参数,则参数值不能为123
                //注意此时不带username等于值为null,也满足条件
    params = {"username","pwd!=123","id=123"} //请求必须满足以上所有规则
    

    headers:设置请求头信息,支持简单的表达式
    consumes:规定请求头中Content-type信息
    produces:告诉浏览器响应的类型是什么,等于给响应头加上Content-type信息

    1. @RequestMapping的模糊匹配功能
      ?:能替代任意一个字符


      ?
      访问成功

    *:能替代任意夺个字符和一层路径


    *替代字符 访问成功 *替代路径 访问成功

    **:能替代多层路径


    ** 访问成功

    注意:当满足多个匹配条件时,精确度高的匹配优先度更高(明确 > ? > * > **),例如有haha和h?h?,但是指定资源不同,访问haha会访问haha指定的精确资源而不会访问模糊匹配的资源

    1. 路径中可以有占位符,效果就是占据一层路径,可以是任意字符,搭配@PathVariable注解可以获取路径中占位符处的值


      获取值
    测试结果

    REST风格的URL

    REST:(资源)表现层状态转化
    springMVC支持REST风格的URL

    传统的url区分CRUD操作:
    获取:/getInfo?id=1
    更新:/updateInfo?id=1
    删除:/deleteInfo?id=1
    添加:/addInfo

    当操作多了,取名会很多,很复杂
    而rest的思想就是,URL统一为/资源名/资源表示符,转而使用不同的提交方式来区分CRUD操作

    rest风格url区分CRUD:
    获取:/Info?id=1 使用GET方式提交
    更新:/Info?id=1 使用PUT方式提交
    删除:/Info?id=1 使用DELETE方式提交
    添加:/Info 使用POST方式提交

    问题:从页面只能发出get和post两种请求,怎么办?

    测试:使用rest风格的url完成CRUD实验
    环境搭建:
    在controller类中根据四种不同的请求方式,给页面传递不同的信息,模拟CRUD操作

    @Controller
    public class myController {
        @RequestMapping(value = "/info/{sid}",method = RequestMethod.GET)
        public String getInfo(@PathVariable("sid")Integer id, Model model) {
            model.addAttribute("msg","成功获取了"+id+"号学生的信息");
            return "success";
        }
    
        @RequestMapping(value = "/info",method = RequestMethod.POST)
        public String addInfo(Model model) {
            model.addAttribute("msg","成功添加了新的学生的信息");
            return "success";
        }
    
        @RequestMapping(value = "/info/{sid}",method = RequestMethod.DELETE)
        public String deleteInfo(@PathVariable("sid")Integer id, Model model) {
            model.addAttribute("msg","成功删除了"+id+"号学生的信息");
            return "success";
        }
    
        @RequestMapping(value = "/info/{sid}",method = RequestMethod.PUT)
        public String updateInfo(@PathVariable("sid")Integer id, Model model) {
            model.addAttribute("msg","成功更新了"+id+"号学生的信息");
            return "success";
        }
    }
    
    页面运行结果

    简单测试后发现,因为页面无法发出除了get和post之外的请求,所以点击获取学生信息和增加学生信息可以正常跳转,但是点击更新和删除学生信息默认是以get方式发送请求,所以跳转的依然是获取学生信息的页面

    解决方案:
    在web.xml中,配置HiddenHttpMethodFilter过滤器


    HiddenHttpMethodFilter

    在index.jsp页面中,将删除、更新两个超链接更换为post提交方式的表单,并且在表单内添加name属性为"_method",value值为对应提交方式的input标签


    页面

    之后提交这两个表单就会以name属性为"_method"的input标签的value值规定的方式进行提交

    注意:如果使用Tomcat8.0+版本进行测试,会报错,应为Tomcat8之后的版本默认不允许PUT、DELETE等提交方式


    错误信息

    解决方法:在跳转之后的jsp页面上,将isErrorPage值设置为true


    isErrorPage
    这之后就可以正常执行了

    原理:
    观察HiddenHttpMethodFilter过滤器的原码可以发现


    原理

    请求处理

    1. 获取请求参数的值
      默认方式获取参数值:
      直接在方法形参中添加和参数值名称类型相同的属性即可获取


      页面
    形参 测试结果
    1. 当username形参已经在方法中大量使用,此时将请求参数名称改为user,则需要大量的修改,此时可以使用@RequestParam("user")注解来修改获取的参数名称
      @RequestParam
      此时使用user可以传递参数
      测试结果
      但是@RequestParam指定的请求参数,默认是必须要有的,即设置之后,请求不能不带这个参数,可以为空,但不能没有,没有就报错
      错误
      可以通过设置@RequestParam的属性来解决这个问题
      required:是否可以为null,true表示不能为null,false表示可以
      设置
      测试结果

    defaultValue:设置默认值,即传空的数据,会默认使用这个数据

    defaultValue 测试结果

    注意,设置默认值之后,即使不设置required属性,也可以为null,为null时,也是用默认值


    测试结果
    1. 获取请求头的信息
      使用方法与@RequestParam一致


      @RequestParam
    测试结果
    若请求参数中没有指定的请求头信息,就会报错,此时也可以通过设置属性来解决问题,属性required和defaultValue使用方法效果与@RequestParam一致
    1. 获取cookie信息
      使用@CookieValue可以根据key值获取cookie中对应的值


      @CookieValue
    测试结果
    若cookie中没有指定的key信息,则报错,此时也可以通过设置属性来解决问题,属性required和defaultValue使用方法效果与@RequestParam一致
    1. 自动封装pojo类以及级联封装
      springmvc强大的功能,可以直接根据参数名自动封装到对应的pojo类中
      创建表单


      表单

      根据表单创建实体类


      实体类
      修改方法,设置对应实体类的形参
      修改方法
      测试
      测试结果

    问题:
    1、如果有比实体类更多的请求参数

    表单
    例如111,则springmvc只会将和实体类set方法名称相同的参数封装到实体类中
    2、级联属性封装需要使用级联属性.属性的方式设置请求参数名
    3、tomcat8之后,默认解决了get获取中文的乱码问题,而8之前的版本需要将tomcat的server.xml种8080端口后加上编码格式才能不乱吗
    4、使用post请求方式会出现乱码问题
    问题
    解决方式:在web.xml中配置CharacterEncodingFilter过滤器,解决乱码
    CharacterEncodingFilter
    CharacterEncodingFilter必须配置在所有过滤器之前,应为要在获取请求的第一时间先解决乱码问题
    测试结果
    6、如果是delete、put等请求方式,解决方案和post一致,因为本质上他们都是post请求方式
    7、springmvc支持直接使用原生API
    原生API

    传输数据到页面

    1. 使用Model、ModelMap、Map集合共享数据


      代码
    测试结果

    共同点:
    通过这三种方式共享的数据,都在requestScope域中,且他们都是通过实现了BindingAwareModelMap实现了共享数据的功能,本质上是同一个东西

    实现方式
    1. 使用@SessionAttributes可以将放在请求域中的数据copy一份到session域中,使用key值直接指定或使用type指定类型,但是有bug,所以想共享数据到session中,建议使用原生api,可控,易删除


      原生API使用session

    转发&重定向

    当视图解析器的前缀和后缀设置好之后,若想去其他路径下的页面,可以使用../跳到上一级页面


    上一级页面

    也可以使用转发,使用forward:+路径可以跳过视图解析器的拼串环节

    代码 测试结果

    或者重定向,传统重定向需要带上虚拟目录路径,而在springmvc中,框架会自动帮我们添上


    代码 测试结果

    二者的区别是转发只能在服务器内部资源中跳转,而重定向可以跳转到其他服务器的资源

    重定向

    且转发可以共享数据,而重定向不行

    相关文章

      网友评论

        本文标题:SpringMVC配置

        本文链接:https://www.haomeiwen.com/subject/xztfwhtx.html