SpringMVC

springMVC是web层框架。

之前javaweb时,servlet中总重复很多封装参数实体之类的公有行为,可使用baseServlet或filter抽取一个前端控制器。现在springMVC也可作为前端控制器。

springMVC可通过一套注解让Java类直接变为处理请求的控制器,无需实现任何接口如servlet的HttpServlet接口。

SpringMVC快速入门

mavenWeb项目,pom文件引入spring-webmvc、servlet、jsp的依赖:
<?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>org.example</groupId>
    <artifactId>SpringModule</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.0.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.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>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>8080</port>
                    <path>/SpringMvcModule</path><!--虚拟目录-->
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
web.xml文件配置springMVC前端控制器
<?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">
    <!--配置SpringMVC的前端控制器:
    配置一个servlet,类选择第三方org.springframework的DispatcherServlet
    配置该类,且路径为拦截所有来作为springMvc的前端控制器servlet  -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param><!--该servlet的初始化参数-->
            <!--spring-mvc.xml是怎么加载的呢
            spring-mvc.xml是怎么加载的呢
            类似web.xml中的<context-param>application域的全局初始化参数。
            这里下面配置初始化参数spring-mvc.xml名称即为web.xml中该DispatcherServlet的servlet的init初始化参数来提供,
            以便org的DispatcherServlet根据这个servlet的init初始化参数去加载springMVC的配置文件,
            继而IOC出controller(特有行为)实例提供给前端控制器DispatcherServlet(共有行为)使用。
            -->
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup><!--loadOnStartup=负整数或不加默认第一次访问该servlet执行时创建servlet对象并初始化
        loadOnStartup为0或正整数时,web服务器启动时创建servlet对象,数字越小,优先级越高-->
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern><!-- 配置该servlet的路径为拦截所有/,虽会覆盖tomcat静态资源访问路径,但现在没有静态资源html之类,只有jsp动态页面。-->
    </servlet-mapping>
</web-app>
com.kdy.controller包中创建UserController
@Controller
public class UserController {
    @RequestMapping("/quickStart")//资源路径
    public String save(){
        System.out.println("Controller save running...");
        return "success.jsp";//springMVC的跳转方式
        /* return "forward:/hello.jsp";//不写forward也默认forward
           return "redirect:/hello.jsp";//重定向,且springMvc会自动加上重定向的虚拟路径             */
    }
}
resource目录下仅创建spring-mvc.xml配置文件

里面加上spring中学的组件扫描注解,以便@controller 被扫描到从而生成实例。

这里仅创建spring-mvc.xml配置文件即可,无需创建applicationContext.xml。

<?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 http://www.springframework.org/schema/context/spring-context.xsd
    ">
    <!--Controller的组件扫描-->
    <context:component-scan base-package="com.kdy">
        <!--里面可加子标签:
             <context:include-filter type="annotation" expression="具体包名或具体到类"代表扫描包含的内容,
            <context:exclude-filter type="annotation" expression="具体包名或具体到类"代表不包含的包内容。-->
    </context:component-scan>
</beans>
webapp中jsp目录创建success.jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>success</title>
</head>
<body>
<h1>success!</h1>
</body>
</html>
配置tomcat部署运行访问如下路径资源即可

http://localhost:8080/SpringMvcModule/quick

spring-mvc.xml是怎么加载的呢

类似web.xml中的<context-param>application域的全局初始化参数。这里的spring-mvc.xml名称也作为web.xml中servlet的init初始化参数来提供,以便org的DispatcherServlet根据这个servlet的init初始化参数去加载springMVC的配置文件,继而IOC出controller(特有行为)实例提供给前端控制器DispatcherServlet(共有行为)使用。

springMVC作为前端控制器获取请求资源地址,继而映射访问真实资源controller。

SpringMvc执行流程

浏览器访问tomcat,路径发给前端控制器,先通过HandlerMapping(类似Filter)返回个处理器执行链(器对象)给前端控制器,前端控制器再把该执行链发给HandlerAdaptor处理,继而发给Handler(即controller)处理,再而Adaptor返回ModelAndView(如jsp)给前端控制器,前端控制器再通过视图解析器将jsp解析为html之类,再返回给前端控制器转发浏览器渲染。

SpringMVC注解

@RequetMapping  加在类上表示请求URL的第一级访问目录,controller较多时好作为区分模块;加在方法上表示URL的第二级访问目录。

一级访问目录加上二级访问目录组成资源的访问虚拟路径。

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/quick")
    public String save() {
        System.out.println("Controller save running...");
        /*
        1.如果类上不加@RequestMapping("/user"),且hello.jsp在webapp根目录下,直接return "hello.jsp";
        则访问http://localhost:8080/SpringMvcModule/quick会return到webapp根目录下的hello.jsp访问成功。
        2.但如果在类上加上@RequestMapping("/user"),且hello.jsp在webapp根目录下,且直接return "hello.jsp";
        则访问http://localhost:8080/SpringMvcModule/user/quick时,就访问不到hello.jsp。
        原因是:这里return "hello.jsp";因为类上加了@RequestMapping("/user"),就默认访问的是webapp目录下的user目录下的hello.jsp,没有这个user目录所以找不到。
        解决方式:return "/hello.jsp";即可。在return的hello.jsp字符串前面加一个/斜线即可。仍然return到webapp根目录下的hello.jsp
        */
        return "/hello.jsp";
        /* return "forward:/hello.jsp";//不写forward也默认forward
           return "redirect:/hello.jsp";//重定向 且springMvc会自动加上重定向的虚拟路径            */
    }
    /*
    * @RequestMapping的参数属性
    * method = RequestMethod.GET表示请求方法必须为GET才允许访问该资源
    * params参数限定,必须有无某些参数或值为多少才允许访问资源,支持简单的表达式。
    * params={"name"}表示请求参数必须有name才允许访问该资源
    * params={"age!30"}表示请求参数age不为30才允许访问该资源
    * headers = {"Cookie"}表示请求头必须携带Cookie才允许访问...
    * */
    @RequestMapping(value = "/quick",method = RequestMethod.GET,params={"name","age!30"},headers = {"Cookie"})
      public String save2() {
        System.out.println("Controller save running...");
        return "/hello.jsp";
        /* return "forward:/hello.jsp";//不写forward也默认forward
           return "redirect:/hello.jsp";//重定向  且springMvc会自动加上重定向的虚拟路径           */
    }
}

SpringMvc配置视图解析器(xml方式)

SpringMvc组件解析 

我们引入spring-webmvc的依赖后,可在External Libraries中看找到org的spring-webmvc目录,点开jar包,找到web.servlet找到DispatcherServlet.properties中有相应的组件配置。

从而我们可用选中具体的类双击shift查看源码。

 SpringMvc配置视图解析器(xml方式)

spring-webmvc的DispatcherServlet.properties配置的InternalResourceViewResolver继承的父类UrlBasedViewResolver中定义了FORWARD_URL_PREFIX=“forward”和REDIRECT_URL_PREFIX= "redirect:",所以我们上面controller直接return省略了转发的前缀,我们也可以手动加上如return "forward:/success.jsp",如果要重定向需要手动加上如:return "redirect:/success.jsp"

配置return的内容的前缀和后缀
resource下的spring-mvc.xml
<?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 http://www.springframework.org/schema/context/spring-context.xsd
    ">
    <!--Controller的组件扫描-->
    <context:component-scan base-package="com.kdy"></context:component-scan>
    <!--配置内部资源视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/jsp"></property><!--前缀-->
        <property name="suffix" value=".jsp"></property><!--后缀-->
    </bean>
</beans>
webapp目录下有jsp目录下的success.jsp文件
com.kdy.controller中UserController中的return语句即可写为
@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/quick")
    public String save() {
        System.out.println("Controller save running...");
        return "/success";
        //return "redirect:/jsp/success.jsp";//重定向的话路径写全名
        //如果return的内容有redirect:或forward:修饰,则配置的视图解析器前缀后缀不生效
        //注:重定向时的虚拟路径不用加也行,springMvc会自动加上重定向的虚拟路径
    }
}

SpringMvc数据响应方式

1.页面跳转:直接return 字符串跳转页面、通过return ModuleAndView对象跳转页面

2.回写数据:返回字符串数据、返回对象或集合

页面跳转--返回字符串跳转页面

直接return 字符串跳转页面见上。

页面跳转--返回ModuleAndView对象跳转页面

com.kdy.controller中的UserController
@Controller
@RequestMapping("/user")
public class UserController {

    /*方法体内new一个modelAndView,返回modelAndView*/
    @RequestMapping("/quick")
    public ModelAndView save() {
        System.out.println("Controller save running...");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("name", "zhangsan");//放到request域中
        modelAndView.setViewName("/success");//这里字符串会经过xml中配置的视图解析器处理,拼上前缀后缀,请求转发
/*        modelAndView.setViewName("forward:/jsp/success.jsp");
          modelAndView.setViewName("redirect:/jsp/success.jsp");
          如果内容有redirect:或forward:修饰,则配置的视图解析器前缀后缀不生效*/
          //注:重定向的虚拟路径:springMvc会自动加上重定向的虚拟路径
        return modelAndView;
    }

    /*入参的参数中注入ModuleAndView对象,返回modelAndView*/
    @RequestMapping("/quick2")
    public ModelAndView save2(ModelAndView modelAndView) {
        System.out.println("Controller save2 running...");
        modelAndView.addObject("name", "zhangsan");//放到request域中
        modelAndView.setViewName("/success");//这里字符串会经过xml中配置的视图解析器处理,拼上前缀后缀,请求转发
        return modelAndView;
    }

    /*返回String字符串跳转具体页面,入参参数中注入model对象,设置其request域携带的数据*/
    @RequestMapping("/quick3")
    public String save3(Model model) {
        System.out.println("Controller save3 running...");
        model.addAttribute("name", "zhangsan");//放到request域中
        return "/success";//这里字符串会经过xml中配置的视图解析器处理,拼上前缀后缀,请求转发
    }

    /*返回String字符串跳转具体页面,原生HttpServletRequest传参:
    * 不常用,我们常用上面几种框架提供的对象,方便与javaWeb解耦
    * */
    @RequestMapping("/quick4")
    public String save4(HttpServletRequest request) {
        System.out.println("Controller save4 running...");
        request.setAttribute("name", "zhangsan");//放到request域中
        return "/success";//这里字符串会经过xml中配置的视图解析器处理,拼上前缀后缀,请求转发
    }
}
webapp下jsp中有个success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>success</title>
</head>
<body>
<h1>success</h1>
name:${name}
</body>
</html>

回写数据--返回字符串数据 

com.kdy.controller包中UserController
@Controller
@RequestMapping("/user")
public class UserController {
    /*借助入参注入的HttpServletResponse对象,回写字符串到网页。回参为void*/
    @RequestMapping("/quick")
    public void save(HttpServletResponse response) throws IOException {
        System.out.println("Controller save running...");
//        response.getWriter().write("hello String response print");
        response.getWriter().println("hello String response print");
    }
    /*借助SpringMvc注解@ResponseBody,return 字符串会作为数据字符串回写网页
      如果有中文乱码,需要设置produces 如@RequestMapping(value = "/save",produces = "text/html;charset=UTF-8")*/
    @RequestMapping("/quick2")
    @ResponseBody
    public String save2(){
        return "hello @ResponseBody String";
    }
}

回写数据--返回字符串数据:对象转json字符串

pom文件除了引入spring-webmvc、servlet、jsp三个依赖外,再引入以下1+3个依赖

fastjson依赖可单独使用,对应下面controller代码中的/quick3的save3方法。

jackson-core和jackson-databind和jackson-annotation三个依赖需一起使用,对应下面controller代码中/quick2的save2方法。

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.74</version>
        </dependency>
        <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>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.10.3</version>
        </dependency>
com.kdy.domain中创建User类(get、set、toString)
public class User {
    private String name;
    private int age;
    //get、set、toString
}
com.kdy.controller中的UserController
@Controller
@RequestMapping("/user")
public class UserController {

    /*@ResponseBody返回字符串,手写json*/
    @RequestMapping("/quick")
    @ResponseBody
    public String save() {
        return "{\"name\":\"zhangsan\",\"age\":18}";
    }

    /*@ResponseBody返回字符串,借助(jackson-core和jackson-databind和jackson-annotation三个依赖)的json转换工具,
    将对象转json
      如果有中文乱码,需要设置produces 如@RequestMapping(value = "/save",produces = "text/html;charset=UTF-8")**/
    @RequestMapping("/quick2")
    @ResponseBody
    public String save2() throws JsonProcessingException {
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(user);
        return json;
    }

    /*@ResponseBody返回字符串,借助(fast-json依赖的)json转换工具,将对象转json*/
    @RequestMapping("/quick3")
    @ResponseBody
    public String save3() throws JsonProcessingException {
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        String json = JSON.toJSONString(user);
        //User user = JSON.parseObject(jsonStr,User.class);
        return json;
    }
}

回写数据--返回对象或集合

我们引入spring-webmvc的依赖后,可在External Libraries中看找到org的spring-webmvc目录,点开jar包,找到web.servlet找到DispatcherServlet.properties中有相应的组件配置。

从而我们可用选中具体的类双击shift查看源码。

配置适配器HandlerAdapter(定义json转换器)

spring-webmvc的依赖的DispatcherServlet.properties中的HandlerAdapter配置中有一个类是RequestMappingHandlerAdapter,双击shift跟进后有一个参数messageConverters并提供了set方法。所以我们就可以通过spring-mvc.xml配置文件给这RequestMappingHandlerAdapter适配器去注入一个json的转换器的属性。

spring-mvc.xml中配置处理器映射器
<?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 http://www.springframework.org/schema/context/spring-context.xsd
    ">
    <!--Controller的组件扫描-->
    <context:component-scan base-package="com.kdy"></context:component-scan>
    <!--配置内部资源视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/jsp"></property><!--前缀-->
        <property name="suffix" value=".jsp"></property><!--后缀-->
    </bean>
    <!--配置处理器映射器-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
            </list>
        </property>
    </bean>
</beans>
com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {

    /*@ResponseBody返回对象,实际经过是配置的转换器将该对象转成json后在发给下一步(视图解析器等响应给网页)*/
    @RequestMapping("/quick")
    @ResponseBody
    public User save() {
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }
}

SpringMvc注解驱动

springMVC多个组件中,处理器映射器、处理器适配器、视图解析器称为三大组件。 

上面使用@ResponseBody加spring-mvc.xml中配置处理器映射器的json的转换器返回对象的配置xml方式比较繁琐。

我们可用使用一个springmvc的注解驱动<mvc:annotation-driven/>来自动加载处理器映射器和处理器适配器。且底层默认继承jackson进行对象或集合的json格式字符串转换。

换句话说,使用<mvc:annotation-driven/>可替代上面spring-mvc.xml配置的处理器映射器。

resource下的spring-mvc.xml文件就改为了
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    ">
    <!--Controller的组件扫描-->
    <context:component-scan base-package="com.kdy"></context:component-scan>
    <!--配置内部资源视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/jsp"></property><!--前缀-->
        <property name="suffix" value=".jsp"></property><!--后缀-->
    </bean>
    <mvc:annotation-driven/>
</beans>
con.kdy.controller的UserController
@Controller
@RequestMapping("/user")
public class UserController {

    /*@ResponseBody返回对象,实际经过是配置的转换器将该对象转成json后在发给下一步(视图解析器等响应给网页)*/
    @RequestMapping("/quick")
    @ResponseBody
    public User save() {
        User user = new User();
        user.setName("zhangsan");
        user.setAge(18);
        return user;
    }
}

SpringMvc获得请求参数

基本数据类型、POJO类型数据、数组类型参数、集合类型参数

基本类型、POJO、数组、集合类型

com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {

    /*springMvc获取基本数据类型请求参数
    *
    * 需要请求参数名和controller中资源方法的入参参数名完全一致。
    * 请求参数名和入参对应后,springmvc会自动类型转换,将前端String类型转成其他类型。
    * 访问:http://localhost:8080/SpringMvcModule/user/quick?name=zhangsan&age=18
    * */
    @RequestMapping("/quick")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save(String name,int age) {
        System.out.println(name);
        System.out.println(age);
    }
    
    /*springMvc获取POJO数据类型请求参数
    *
    * 需要请求参数名称和controller中资源方法的入参POJO对象的属性名(能在POJO属性中找到)完全一致,
    * springMvc会自动封装,即springMvc实例入参对象时会将属性注入
    * 访问:http://localhost:8080/SpringMvcModule/user/quick2?name=zhangsan&age=18
    * */
    @RequestMapping("/quick2")
    @ResponseBody
    public void save2(User user) {
        System.out.println(user);
    }


    /*springMvc获取数组类型请求参数
     *
     * 需要请求参数名称和controller中资源方法的入参数组名完全一致,
     * 参数值会自动映射匹配
     * 访问:http://localhost:8080/SpringMvcModule/user/quick3?strs=aaa&strs=bbb&strs=ccc
     * */
    @RequestMapping("/quick3")
    @ResponseBody
    public void save3(String[] strs) {
        System.out.println(Arrays.asList(strs));
    }

    /*springMvc获取集合类型请求参数:方式一:创建VO类封装集合
     *
     * springMvc暂未提供集合类型自动封装工具,故不可写(List<User> userList)这种入参。
     * 我们可用借助springMvc封装Pojo类型的方式,创建一个类,将List<User> userList作为成员属性,并提供set方法
     * 这样对于前端的集合类型参数,即可自动注入到该类实例中。我们称这个类为VO。
     * 访问:http://localhost:8080/SpringMvcModule/jsp/form.jsp
     * 具体jsp文件见webapp下jsp的form.jsp 通过表单发送post请求到本资源
     * */
    @RequestMapping("/quick4")
    @ResponseBody
    public void save4(VO vo) {
        System.out.println(vo);
    }

    /*springMvc获取集合类型请求参数:方式二:对于Ajax请求传递过来的json格式的List集合
     * 直接使用@RequestBody 加json前的类型,spring自动将json转成对象
     *
     * 通过webapp目录下js目录下引入jQuery-3.7.0.js官网下载
     * 通过webapp下jsp下创建ajax.jsp,通过script发jquery的ajax请求,创建List<User>集合数据并转json发送到本资源
     * 注:js属于静态资源,载web.xml中配置了前端控制器配成了/拦截了所有资源去发配给controller,所以
     * 我们要载spring-mvc.xml中配置静态资源放行<mvc:resources location="/" mapping="/星星/星.js"/>
     * */
    @RequestMapping("/quick5")
    @ResponseBody
    public void save5(@RequestBody List<User> userList) {
        System.out.println(userList);
    }
}
com.kdy.domain中的User:生成get、set、toString
public class User {
    private String name;
    private int age;
}
/quick4用到的VO,com.kdy.domain中的VO:get、set、toString
public class VO {
    private List<User> userList;
}
/quick4用到的webapp下jsp下的form.jsp里bady里的内容
<form action="${pageContext.request.contextPath}/user/quick4" method="post">
    user1:<br/>
    name:<input type="text" name="userList[0].name"><br/>
    <%--这里form表单input的name如果走springMvc封装POJO参数需要和POJO属性名完全一致
        访问资源路径方法的入参是VO类,其属性为List<User> userList,
        由于是集合类型我们可用用userList[0]这种下标方式传值入参,
        再如如果VO中的属性是User user,我们可用user.name和user.age继续赋值,
        类推这里我们可用userList[0].name和userList[0].age进行对各下标的数组元素进行赋值
    --%>
    age:<input type="text" name="userList[0].age"><br/>
    user2:<br/>
    name:<input type="text" name="userList[1].name"><br/>
    age:<input type="text" name="userList[1].age"><br/>
    user3:<br/>
    name:<input type="text" name="userList[2].name"><br/>
    age:<input type="text" name="userList[2].age"><br/>
    <input type="submit" value="submit">
</form>
/quick5用到的webapp下的js目录下的jQuery-3.7.0.js从官网下载
/quick5用的的webapp下的jsp下的ajax.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>ajax</title>
</head>
<body>
</body>
<script src="${pageContext.request.contextPath}/js/jquery-3.7.0.js"></script>
<script>
    var userList = new Array();
    userList.push({username:"zhangsan",age:18});
    userList.push({username:"zhangsan2",age:20});
    $.ajax({
        type:"POST",
        url:"${pageContext.request.contextPath}/user/quick5",
        data:JSON.stringify(userList),
        contentType:"application/json;charset=utf-8"
    });
</script>
</html>
/quick5用到的,spring-mvc.xml中静态资源放行
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    ">
    <!--Controller的组件扫描-->
    <context:component-scan base-package="com.kdy"></context:component-scan>
    <!--配置内部资源视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/jsp"></property><!--前缀-->
        <property name="suffix" value=".jsp"></property><!--后缀-->
    </bean>

    <!--注解驱动,顶替配置的处理器映射器和适配器,集成了jackson,可Controller资源方法返回字为对象User时,自动转为json-->
    <mvc:annotation-driven/>

    <!--js和css和html等被web.xml中配置的前端控制配置拦截了,
      这里配置springMvc静态资源放行-->
    <!--springMvc开放静态资源的访问路径。mapping表示的是映射地址,location表示的是哪个目录下的资源是对外开放的-->
    <mvc:resources mapping="/js/**" location="/js/"/><!--就表示访问路径为/js/**时,在/js/目录下的资源是对外开放的-->
<!--    <mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/html/**" location="/html/"/>-->
    <!--上面的<mvc:resources location="/" mapping="/**/*.js"/>等等也可配置为以下代码-->
<!--    <mvc:default-servlet-handler/> 若使用这种方式,必须配置注解驱动,否则controller无法访问-->
    <!-- 意思就是在访问资源时,springMvc帮我们找对于controller的地址,
    如果找不到,就交给原始容器tomcat容器帮我们找静态资源的地址。-->
</beans>

spring-mvc.xml中静态资源放行

    <!--js和css和html等被web.xml中配置的前端控制配置拦截了,
      这里配置springMvc静态资源放行-->
    <!--springMvc开放静态资源的访问路径。mapping表示的是映射地址,location表示的是哪个目录下的资源是对外开放的-->
    <mvc:resources mapping="/js/**" location="/js/"/><!--就表示访问路径为/js/**时,在/js/目录下的资源是对外开放的-->
<!--    <mvc:resources mapping="/css/**" location="/css/"/>
    <mvc:resources mapping="/html/**" location="/html/"/>-->
    <!--上面的<mvc:resources location="/" mapping="/**/*.js"/>等等也可配置为以下代码-->
<!--    <mvc:default-servlet-handler/>若使用这种方式,必须配置注解驱动,否则controller无法访问-->
    <!-- 意思就是在访问资源时,springMvc帮我们找对于controller的地址,
    如果找不到,就交给原始容器tomcat容器帮我们找静态资源的地址。-->

请求参数乱码问题

tomcat8的post请求存在中文乱码问题,javaWeb阶段req.setCharacterEncoding("UTF-8")来解决,现阶段可在web.xml中设置SpringMvc的字符编码过滤器的filter来解决。

注:web.xml标签需要遵循一定顺序来写,否则不生效。

webapp的WEB-INF的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">
    <!--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>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--配置SpringMVC的前端控制器:-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
还是上面请求参数的案例,重启tomcat,进入8080/SpringMvcModule/jsp/form.jsp​​​​​​

输入一些中文字符点击提交表单,就会post请求提交到/quick4路径的controller里了。

SpringMvc参数绑定注解@RequestParam

如请求参数和controller方法中的入参参数名不完全一样,可用借助@RequestParam映射

@Controller
@RequestMapping("/user")
public class UserController {
    /*若controller入参参数名和请求参数名不完全一致可用@RequestParam绑定请求参数到入参参数上
    * 访问http://localhost:8080/SpringMvcModule/user/quick?username=zhangsan  不加参数会报错(required默认true)
    * */
    @RequestMapping("/quick")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save(@RequestParam("username") String name) {
        System.out.println(name);
    }
    /*@RequestParam的参数
    * required:指定的请求参数是否必须包含,默认true,提交时如果没有该参数会报错
    * defaultValue:如果没有指定请求参数,则使用默认值赋值
    * 访问http://localhost:8080/SpringMvcModule/user/quick
    * */
    @RequestMapping("/quick2")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save2(@RequestParam(value = "username",required = false,defaultValue = "zhangsanDefault") String name) {
        System.out.println(name);
    }
}

获得Restful风格参数

RestFul使用url+请求参数,如/user/1 GET等等。

Http常用动词GET获取、POST新增、PUT更新、DELETE删除

controller中可用路径中的{name}占位符配合入参中使用@PathVariable(name)String name

@Controller
@RequestMapping("/user")
public class UserController {
    /*
    * 获取Restful风格参数
    * 访问:http://localhost:8080/SpringMvcModule/user/quick/张三
    * @PathVariable参数:required默认true,也只能为true,改成false不生效,还是要传递后面占位符参数如/quick/zhangsan
    *  */
    @RequestMapping("/quick/{name}")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save(@PathVariable("name") String name) {
        System.out.println(name);
    }
}

SpringMvc获取日期参数

@Controller
@RequestMapping("/user")
public class UserController {
    /*
    * 获取日期类型参数
    * 访问 http://localhost:8080/SpringMvcModule/user/quick?date=2021/02/22
    *  */
    @RequestMapping("/quick")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save(Date date) {
        System.out.println(date);
    }
}

日期(yyyy-MM-dd格式)--自定义类型转换器

springMvc提供了一些简单的类中转换器,如请求参数String的age,自动转为int的age入参。

对于Date类型,如果请求参数为date=2021/02/22,这时controller入参为Date date时还是可用springMvc自动转换的。但如果请求参数为date=2021-02-22,就需自定义类型转换器了。

com.kdy.converter包下创建DateConverter类
public class DateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String dateStr) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try{
            date = sdf.parse(dateStr);
        }catch (ParseException e){
            e.printStackTrace();
        }
        return date;
    }
}

spring-mvc.xml中实例化这个转换器工厂的bean,并注入这个自定义转换器实例

且spring-mvc.xml中spring-mvc注解驱动需要配置onversion-service为这个bean的id

resource下的spring-mvc.xml内容如下
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    ">
    <!--Controller的组件扫描-->
    <context:component-scan base-package="com.kdy"></context:component-scan>
    <!--配置内部资源视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/jsp"></property><!--前缀-->
        <property name="suffix" value=".jsp"></property><!--后缀-->
    </bean>
    <!--声明springMvc请求参数为date=2021-02-22时controller入参为Date date的类型转换器
    1.定义这个bean
    2.在springMvc注解驱动中传递这个转换器的bean的id    <mvc:annotation-driven conversion-service="conversionService"/> -->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="com.kdy.converter.DateConverter"></bean>
            </list>
        </property>
    </bean>

    <!--注解驱动,顶替配置的处理器映射器和适配器,集成了jackson,可Controller资源方法返回字为对象User时,自动转为json-->
    <mvc:annotation-driven conversion-service="conversionService"/>
    <!--这里配置springMvc的js静态资源放行-->
    <mvc:resources mapping="/js/**" location="/js/"/>
</beans>
com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {
    /*
    * 获取日期类型参数,如果是请求参数为date=2021/02/22即可springMvc子自动类型转换成controller中的入参Date date
    * 但如果是请求参数为date=2021-02-22格式需要通过配置的自定义转换器类com.kdy.converter的DateConverter和spring-mvc.xml中配置的转换器并使的springMvc注解驱动配置该转换器
    * 访问 http://localhost:8080/SpringMvcModule/user/quick?date=2021-02-22
    *  */
    @RequestMapping("/quick")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save(Date date) {
        System.out.println(date);
    }
}

SpringMvc获得Servlet相关API

只需在controller的方法入参中传递HttpServletRequest、HttpServletResponse、HttpSession即可

@Controller
@RequestMapping("/user")
public class UserController {
    /*
    * springMvc获得Servlet相关API
    *  */
    @RequestMapping("/quick")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
        System.out.println(request);
        System.out.println(response);
        System.out.println(session);
    }
}

SpringMvc获取请求头
 

@RequestHeader获得请求头信息,相当于web里的req.getHeader(name)

@CookieValue参数获得指定的Cookie的值

@Controller
@RequestMapping("/user")
public class UserController {
    /*
    * springMvc获取请求头@RequestHeader
    *  */
    @RequestMapping("/quick")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save(@RequestHeader("Referer") String referer) {
        System.out.println(referer);
    }
    /* springMvc获取请求头@RequestHeader
     * @RequestHeader参数
     * value请求头名称
     * required是否必须请携带此请求头  不写默认为true
     *  */
    @RequestMapping("/quick2")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save2(@RequestHeader(value = "User-Agent",required = false) String user_agent) {
        System.out.println(user_agent);
    }
    /*
     * springMvc获取请求头@CookieValue
     * @CookieValue参数获得指定的cookie的值,即请求头里Cookie的值有很多个分号分开的key:value,这里获取指定的。
     * value请求头名称
     * required是否必须请携带此请求头  不写默认为true
     *  */
    @RequestMapping("/quick3")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save3(@CookieValue("JSESSIONID") String jsessionId) {
        System.out.println(jsessionId);
    }
}

SpringMvc获取文件类型的参数--文件上传

客户端表单文件上传三要数

表单项设置type="file"     表单提交方式设置为post

加上enctype="multipart/form-data",即设置enctype属性为多部分表单形式

在webapp的jsp目录创建uploadFile.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>uploadFile</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/quick" method="post"
      enctype="multipart/form-data">
    名称<input type="text" name="name"><br/>
    文件<input type="file" name="upload"><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>

文件上传原理:

enctype默认="application/x-www-form-urlencoded"这时form表单正文内容格式为key=value&key=value&key=value,req.getParameter()可用使用。

将enctype设置="Mutilpart/form-data"时,请求正文部分变成多部分形式如下:

------------------7de1a433602ac----------

Content-Disposition:form-date;name="name"

zhangsan

------------------7de1a433602ac----------

Content-Disposition:form-data;name="file"

filename="C:\Users\muzimoo\Desktop\文件上传.txt"

Content-Type:text/plain

aaa(txt内容)

bbb(txt内容)

------------------7de1a433602ac----------

这时req.getParameter()将失效。

在web阶段,我们使用阿帕奇的FileUpload插件进行上传文件,在springmvc中也封装了FileUpload插件。

环境准备

导入坐标:commons-fileupload、commons-io

配置文件上传解析器sprinv-mvc.xml中配置“multipartyResolver”

 导入坐标
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
在spring-mvc.xml中配置文件上传解析器
    <!--配置文件上传解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--上传文件的编码类型-->
        <property name="defaultEncoding" value="UTF-8"/>
        <!--上传文件总大小,最大限制,单位byte-->
        <property name="maxUploadSize" value="5242800"/>
        <!--上传单个文件大小,最大限制,单位byte-->
        <property name="maxUploadSizePerFile" value="5242800"/>
    </bean>
单文件上传
form表单见上webapp的jsp目录创建uploadFile.jsp
com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {
    /*
    * springMvc获取单文件参数,单文件上传
    * jsp/uploadFile.jsp提交post请求且type="file"且enctype="multipart/form-data"到本servlet
    *  */
    @RequestMapping("/quick")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save(String name, MultipartFile upload) throws IOException {
        System.out.println(name);
        System.out.println(upload);
        //对文件进行保存,使用transferTo()方法进行保存到服务器或我们本地硬盘上
        String originalFilename = upload.getOriginalFilename();
        upload.transferTo(new File("D:\\img\\"+originalFilename));
    }
}
访问http://localhost:8080/SpringMvcModule/jsp/uploadFile.jsp
多文件上传方式1
webapp的jsp目录创建uploadFile.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>uploadFile</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/quick" method="post"
      enctype="multipart/form-data">
    名称<input type="text" name="name"><br/>
    文件1<input type="file" name="uploadFile1"><br/>
    文件2<input type="file" name="uploadFile2"><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>
com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {
    /*
    * springMvc获取文件参数,多文件上传
    * jsp/uploadFile.jsp提交post请求且type="file"且enctype="multipart/form-data"到本servlet
    *  */
    @RequestMapping("/quick")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save(String name, MultipartFile uploadFile1, MultipartFile uploadFile2) throws IOException {
        System.out.println(name);
        //对文件进行保存,使用transferTo()方法进行保存到服务器或我们本地硬盘上
        String originalFilename1 = uploadFile1.getOriginalFilename();
        uploadFile1.transferTo(new File("D:\\img\\"+originalFilename1));
        String originalFilename2 = uploadFile2.getOriginalFilename();
        uploadFile2.transferTo(new File("D:\\img\\"+originalFilename2));
    }
}
多文件上传方式2
webapp的jsp目录创建uploadFile.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>uploadFile</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/quick" method="post"
      enctype="multipart/form-data">
    名称<input type="text" name="name"><br/>
    文件1<input type="file" name="uploadFile"><br/>
    文件2<input type="file" name="uploadFile"><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>
 com.kdy.controller中UserController
@Controller
@RequestMapping("/user")
public class UserController {
    /*
    * springMvc获取文件参数,多文件上传
    * jsp/uploadFile.jsp提交post请求且type="file"且enctype="multipart/form-data"到本servlet
    *  */
    @RequestMapping("/quick")
    @ResponseBody//返回void时,这里得加上该注解,否则会返回寻找页面,即拼接视图解析器的前后缀,如/jspuser/quick.jsp
    public void save(String name, MultipartFile[] uploadFile) throws IOException {
        System.out.println(name);
        for (MultipartFile file:uploadFile) {
            String originalFilename = file.getOriginalFilename();
            file.transferTo(new File("D:\\img\\"+originalFilename));
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值