zoukankan      html  css  js  c++  java
  • 3、SpringMVC注解式开发

    学习资源:动力节点的2020最新SpringMVC教程【IDEA版】-springmvc从入门到精通



    1、@RequestMapping 请求映射

    在控制器的方法上使用,表示要对 value 属性所指定的 URI 请求进行处理与响应。

    1.1、指定模块名称

    通过 @RequestMapping 注解可以定义控制器对于请求的映射规则。 该注解可以注解在方法上,也可以注解在类上,但意义是不同的。 value 属性值常以 "/" 开始。

    @RequestMapping 的 value 属性用于定义所匹配请求的 URI。但对于注解在方法上与类上,其 value 属性所指定的 URI,意义是不同的。

    一个 @Controller 所注解的类中,可以定义多个控制器方法。当然,不同的控制器方法所匹配的 URI 是不同的。 这些不同的 URI 被指定在注解于方法之上的 @RequestMapping 的 value 属性中。 但若这些请求具有相同的 URI 部分,则这些相同的 URI, 可以被抽取到注解在类之上的 @RequestMapping 的 value 属性中,此时的这个 URI 表示模块的名称。 URI 的请求是相对于 Web 的根目录。

    换个角度说,要访问控制器的指定方法,必须要在方法指定 URI 之前加上控制器类前定义的模块名称。

    @Controller
    public class FirstController {
    
        @RequestMapping("/test/some.do")
        public ModelAndView doSome(){
        }
    
        @RequestMapping("/test/other.do")
        public ModelAndView doOther(){
        }
    }
    //可将相同的 uri 提取到类上
    @Controller
    @RequestMapping("/test")
    public class FirstController {
    
        @RequestMapping("some.do")
        public ModelAndView doSome(){
        }
    
        @RequestMapping("other.do")
        public ModelAndView doOther(){
        }
    }
    

    1.2、定义请求提交方式

    对于 @RequestMapping,其有一个属性 method,用于对被注解方法所处理请求的提交方式进行限制,即只有满足该 method 属性指定的提交方式的请求,才会执行该被注解方法。

    Method 属性的取值为 RequestMethod 枚举常量。常用的为 RequestMethod.GETRequestMethod.POST,分别表示提交方式的匹配规则为 GET 与 POST 提交。

    客户端浏览器常用的请求方式,及其提交方式:

    image-20200904105606401

    不指定 method 属性,则无论是 GET 还是 POST 提交方式,均可匹配,即对于请求的提交方式无要求.

    @RequestMapping("/other.do")
    public ModelAndView doOther(){
    }
    

    指定了控制器方法匹配的请求提交方式为 POST,则相当于指定了请求发送的方式: 要么使用表单请求,要么使用 AJAX 请求,其它请求方式都会被被禁用。

    @RequestMapping(value = {"/other.do"}, method = RequestMethod.POST)
    public ModelAndView doOther(){
    }
    

    指定请求方式为 GET ,则超链接、GET 型表单都可发送请求到控制器。

    @RequestMapping(value = {"/other.do"}, method = RequestMethod.GET)
    public ModelAndView doOther(){
    }
    

    2、控制器方法的参数

    控制器方法可以包含以下四类参数,这些参数会在系统调用时由系统自动赋值,即程序员可在方法内直接使用:

    • HttpServletRequest
    • HttpServletResponse
    • HttpSession
    • Model
    • ModelMap
    • 请求中所携带的请求参数
    @RequestMapping(value = "请求地址")
    public 返回值 自定义方法名(HttpRequest request, 
                      HttpServletResponse response, 
                      HttpSession session, 
                      Model model, 
                      请求中携带参数...){
        
        
    }
    

    2.1、逐个参数接收(控制器方法形参接收)

    若请求中的参数个数较少,则只要保证 uri 中的请求参数名与该请求处理的控制器方法的参数名相同即可,框架会把同名的请求参数赋值给同名的形参,对形参的顺序没有要求。

    SpringMVC 使用 request 对象接收请求参数,String name= request.getParameter("name");String age= request.getParameter("age");,框架会提供类型转换的功能,能把String转为 int ,long , float, double等类型。

    该方式是用于请求参数数量少的情况。

    GET方式方便查看 uri
    <form action="test/register.do" method="GET">
        姓名:<input type="text" name="name"/><br/>
        年龄:<input type="text" name="age" /><br/>
        <input type="submit" value="注册"/>
    </form>
    

    该表单的请求 uri:http://localhost:8082/springmvc/test/register.do?name=Linda&age=15

    @Controller
    @RequestMapping("/test")
    public class FirstController {
    
        @RequestMapping("/register.do", method= RequestMethod.GET)
        public ModelAndView doRegister(Integer age, String name){
            
            ModelAndView mv = new ModelAndView();
            mv.addObject("registerName", );
            mv.addObject("registerAge", );
    
           	mv.setViewName("show");
          
            return mv;
        }
    }
    

    image-20200904114228038


    2.1.2、字符集过滤器解决请求中参数乱码问题

    请求使用 POST 方式,会出现请求中文参数乱码问题。

    <form action="test/register.do" method="POST">
        姓名:<input type="text" name="name"/><br/>
        年龄:<input type="text" name="age" /><br/>
        <input type="submit" value="注册"/>
    </form>
    

    image-20200904114434612

    Spring 对于请求参数中的中文乱码问题,给出了专门的字符集过滤器: spring-web-5.2.5.RELEASE.jar 的
    org.springframework.web.filter 包下的 CharacterEncodingFilter 类。

    <!-- 注册字符集过滤器:解决post请求乱码的问题 -->
    <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>
        <!-- 强制 request 使用 encoding -->
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <!-- 强制 response 使用 encoding -->
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <!-- 指定哪些 url 使用该过滤器,/* 表示所有请求 -->
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    2.1.2、@RequestParam 校正请求参数名

    校正请求参数名,是指若请求 URL 所携带的参数名称与处理方法中指定的参数名不相同时, 则需在处理方法参数前, 添加一个注解@RequestParam("请求参数名"),指定请求 URL 所携带参数的名称。该注解是对控制器方法参数进行修饰的。

    value 属性,String 类型,指定请求参数的名称。

    required boolean 类型,默认是 true,true 表示请求中必须带有参数,false 则反之。如,设置为 true,发送请求:http://localhost:8082/springmvc/test/register.do?r_name=Linda&r_age=15 会出现 400 的错误。

    <form action="test/register.do" method="POST">
        姓名:<input type="text" name="r_name"/><br/>
        年龄:<input type="text" name="r_age" /><br/>
        <input type="submit" value="注册"/>
    </form>
    
    @Controller
    @RequestMapping("/test")
    public class FirstController {
    
        @RequestMapping("/register.do", method= RequestMethod.POST)
        public ModelAndView doRegister(@RequestParam(value="r_age", required=false)Integer age, 
                                       @RequestParam(value="r_name", required=false)String name){
            
        }
    }
    

    2.2、对象接收参数

    若请求中有多个参数,逐个接收参数较为繁琐,可以将控制器方法的参数定义为一个对象,只要保证请求参数名与这个对象的属性同名即可。

    当控制器方法的形参是 Java 对象,SpringMVC 框架会使用参数类的无参构造器创建一个参数对象,并调用 setter 将请求参数一一赋值给参数对象的同名属性。

    定义接收请求参数的类:

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Registrant {
        
        private String name;
        private Integer age;
    }
    
    <form action="test/register.do" method="POST">
        姓名:<input type="text" name="r_name"/><br/>
        年龄:<input type="text" name="r_age" /><br/>
        <input type="submit" value="注册"/>
    </form>
    
    @Controller
    @RequestMapping("/test")
    public class FirstController {
    
        @RequestMapping("/register.do", method= RequestMethod.GET)
        public ModelAndView doRegister(Registrant registrant){
            
            ModelAndView mv = new ModelAndView();
            mv.addObject("name",registrant.getName());
            mv.addObject("age",registrant.getAge());
            mv.addObject("registrant",registrant);
    
           	mv.setViewName("show");
            return mv;
        }
    }
    

    3、控制器方法的返回值

    3.1、返回 ModelAndView

    表示返回 数据+视图。

    若控制器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据, 此时控制器方法返回 ModelAndView 比较好。当然,若要返回 ModelAndView,则控制器方法中需要定义 ModelAndView 对象。

    Model 中的数据被存储在 request 作用域中,SringMVC 默认采用 转发 的方式跳转到视图,本次请求结束后,模型中的数据被销毁。

    modelAndView.addObject("registerName", name);
    modelAndView.addObject("registerAge", age);
    modelAndView.setViewName("show");
    

    在使用时, 若该控制器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何资源跳转(如对页面的 Ajax 异步响应),此时若返回 ModelAndView,则将总是有一部分多余: 要么 Model 多余,要么 View 多余。 即此时返回 ModelAndView 将不合适。


    3.2、返回 String(视图)

    表示返回视图。

    控制器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址;也可以去除视图解析器,使用视图的完整路径名。

    @RequestMapping(value = "/test/register.do", method = RequestMethod.POST)
    public String doRegister(HttpRequest request, Integer age, String name){
        
        request.setAttribute("name", name);
        request.setAttribute("age", age);
    
        //有视图解析器的情况
        return "show";
    }
    

    3.3、返回 void

    对于控制器方法返回 void 的主要应用场景:AJAX 响应(异步请求,页面局部更新)。

    若控制器对请求处理后,无需跳转到其它任何资源,此时可以让控制器方法返回 void。


    导入 GSON 依赖:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.10.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.10.3</version>
    </dependency>
    

    引入 jquery 库,页面发起 ajax 请求:

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
         <script type="text/javascript" src="js/jquery-3.4.1.js"></script>
         <script type="text/javascript">
             $(function(){
                 $("button").click(function(){
                     $.ajax({
                         url:"returnVoid-ajax.do",
                         data:{
                             name:"张三",
                             age:20
                         },
                         type:"post",
                         // dataType 加不加都可以
                         dataType:"json",
                         success:function(resp){
                             //resp从服务器端返回的是json格式的字符串 {"name":"zhangsan","age":20}
                             //jquery会把字符串转为json对象, 赋值给resp形参。
                             alert(resp.name + "" + resp.age);
                         }
                     })
                 })
             })
         </script>
    </head>
    <body>
        <button id="btn">发起ajax请求</button>
    </body>
    </html>
    

    控制器方法:

    @RequestMapping(value = "/returnVoid-ajax.do")
    public void doAjax(HttpServletResponse response, Integer age, String name) throws IOException {
    
        // 处理ajax,使用json做数据的格式,使用 registrant 表示处理结果
        Registrant registrant =  new Registrant("张三", 19);
        // 把结果的对象转为json格式的数据
    
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(registrant);
    
        // 输出数据,响应ajax的请求
        PrintWriter writer = response.getWriter();
        writer.print(json);
        writer.flush();
        writer.close();
    }
    

    3.4、返回 Object

    控制器方法也可以返回 Object 对象。 这个 Object 可以是 Integer, String, 自定义对象,Map, List 等。但返回的对象不是作为逻辑视图出现的,而是作为直接在原页面显示的数据出现。

    主要使用场景:响应 ajax 请求,将响应数据以 json 格式输出到页面。

    返回对象,需要使用 @ResponseBody 注解, 将转换后的 JSON 数据放入到响应体中。

    实现步骤:

    1. 加入处理 json 的依赖。
      由于返回 Object 数据,一般都是将数据转化为了 JSON 对象后传递给浏览器页面的。而这个由 Object 转换为 JSON,是由 Jackson 工具完成的。所以需要导入 Jackson 的相关 Jar 包(springmvc 默认使用 jackson)。
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.10.3</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.10.3</version>
    </dependency>
    
    1. 在 springmvc 配置文件中配声明注解驱动。
      将 Object 数据转化为 JSON 数据,需要由消息转换器 HttpMessageConverter 完成。而转换器的开启,需要由 <mvc:annotation-driven/> 来完成。
      SpringMVC 使用消息转换器 HttpMessageConverter 实现请求数据和对象,控制器方法返回对象和响应输出之间的自动转换。
    <!-- 注解驱动 -->
    <!-- 开启消息转换器 -->
    <mvc:annotation-driven/>
    
    1. 在控制器方法上使用 @ResponseBody 注解,作用是完成下面代码的功能
    PrintWriter pw = reponse.getWrite();
    pw.print(json);
    pw.flush;
    pw.close;
    

    3.4.1、返回自定义类型对象

    @RequestMapping(value = "/returnRegistrant.do")
    @ResponseBody
    public List<Registrant> doReturn() {
    
        Registrant registrant =  new Registrant("张三", 31);
        return registrant;
    }
    

    3.4.2、返回 List

    @RequestMapping(value = "/returnList.do")
    @ResponseBody
    public List<Registrant> doReturnList() {
    
        Registrant registrant1 =  new Registrant("张三", 31);
        Registrant registrant2 =  new Registrant("张三", 31);
        List<Registrant> list = new ArrayList<>();
        list.add(registrant1);
        list.add(registrant2);
        return list;
    }
    

    3.4.3、返回 String

    若要返回非中文字符串,将前面返回数值型数据的返回值直接修改为字符串即可。但若返回的字符串中带有中文字符,则接收方页 面将会出现乱码(中文字符转换为 json 默认使用的是 IOS-8859-1),此时需要使用 @RequestMapping 的 produces 属性指定字符集。

    produces,产品,结果,即该属性用于设置输出结果类型。

    @RequestMapping(value = "/returnString.do", produces="text/plain;charset=utf-8")
    @ResponseBody
    public String doreturnString() {
        
        return "SpringMVC 注解开发真快!";
    }
    

    4、url-pattern

    <url-pattern/> 指定了请求地址与 servlet 的映射关系,如 *.do 的请求要交与 "springmvc " 这个框架的 servlet 处理。

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    

    然而 工程名/index.jsp、工程名/静态资源(.js、.html、.jpg等)在浏览器中可以直接访问到,是谁处理的它们呢?—— Tomcat。为什么 Tomcat 能处理这些请求呢,其原理也是使用 servlet ,其内部有一个名为 default 的 servlet,用来处理静态资源和未映射到其他 servlet 的请求。 "/" 表示 default 要处理的是静态资源。

    <!-- The default servlet for all web applications, that serves static     -->
    <!-- resources.  It processes all requests that are not mapped to other   -->
    <!-- servlets with servlet mappings (defined either here or in your own   -->
    <!-- web.xml file).  												  -->
    <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.1、*.后缀

    在没有特殊要求的情况下, SpringMVC 的中央调度器 DispatcherServlet 的 <url-pattern/> 常使用后辍匹配方式,如写为 *.do 或者 *.action 、 *.mvc 等。

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.do</url-pattern>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
    

    4.2、/

    / 表示映射所有的请求到 DispatcherServlet,包括静态资源和动态资源的请求。

    当给 DispatcherServlet 的映射配置为 "/" 后,DispatcherServlet 会替代 default ,但是默认情况下 DispatcherServlet 没有处理静态资源的能力,因为控制器不能访问静态资源,这样就会造成所有静态资源无法访问,404。

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    

    4.3、静态资源访问

    <url-pattern/> 的值并不是说写为 / 后,静态资源就无法访问了,经过一些配置后,该问题也是可以解决的。

    4.3.1、声明 <mvc:default-servlet-handler/>

    在 springmvc 配置文件中声明 <mvc:default-servlet-handler/>

    声明了 <mvc:default-servlet-handler /> 后,springmvc 框架会在容器中创建 DefaultServletHttpRequestHandler 处理器对象,它会像一个检查员,对进入 DispatcherServlet 的 URL 进行筛查,如果发现是访问静态资源的请求,就将该请求转由 Web 应用服务器默认的 Servlet 处理(一般的服务器都有默认的 Servlet)。

    <mvc:default-servlet-handler/>
    

    4.3.2、声明 <mvc:resources/>

    在 Spring3.0 版本后, Spring 定义了专门用于处理静态资源访问请求的处理器 ResourceHttpRequestHandler。并且添加了<mvc:resources/>标签,专门用于解决静态资源无法访问问题。 需要在 springmvc 配置文件中添加如下形式的配置:

    <!-- 为webapp下的每个类别的静态资源一一进行映射 -->
    <!-- url 中的 ** 表示该路径的所有请求 -->
    <mvc:resources mapping=" /images/**" location="/images/"/>
    <mvc:resources mapping="/html/**" location="/html/" />
    <mvc:resources mapping="/js/**" location="/js/"/>
    ......
    

    还是太麻烦!将静态资源统一放置在 webapp/static/ 下:

    <mvc:resources mapping="/static/**" location="/static/"/>
    

    4.3.3、为1、2方式声明注解驱动

    不使用服务器自带的 servlet 处理静态资源,使用上面两种方式处理的话,会发生动态资源和静态资源冲突的问题,为此需要在 springmvc 配置文件加入:

    <mvc:annotation-driven/>
    
  • 相关阅读:
    MySQL临时表
    git开发常用命令
    PHP资源列表
    Golang学习--平滑重启
    Golang学习--TOML配置处理
    Golang学习--包管理工具glide
    Golang学习--开篇
    构建自己的PHP框架--构建模版引擎(3)
    构建自己的PHP框架--构建模版引擎(2)
    Laravel Session 遇到的坑
  • 原文地址:https://www.cnblogs.com/sout-ch233/p/13622421.html
Copyright © 2011-2022 走看看