1.什么是SpringMVC

1.1、什么是MVC

  • MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
  • 是将业务逻辑、数据、显示分离的方法来组织代码。
  • MVC主要作用是降低了视图与业务逻辑间的双向偶合
  • MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。

Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。

View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。

Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。

最典型的MVC就是JSP + servlet + javabean的模式。

1.2、Spring概述

SpringMVC-LMLPHP

Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。

查看官方文档:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#spring-web

我们为什么要学习SpringMVC呢?

Spring MVC的特点:

  1. 轻量级,简单易学
  2. 高效 , 基于请求响应的MVC框架
  3. 与Spring兼容性好,无缝结合
  4. 约定优于配置
  5. 功能强大:RESTful、数据验证、格式化、本地化、主题等
  6. 简洁灵活

Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计。

DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解形式进行开发,十分简洁;

正因为SpringMVC好 , 简单 , 便捷 , 易学 , 天生和Spring无缝集成(使用SpringIoC和Aop) , 使用约定优于配置 . 能够进行简单的junit测试 . 支持Restful风格 .异常处理 , 本地化 , 国际化 , 数据验证 , 类型转换 , 拦截器 等等......所以我们要学习 .

最重要的一点还是用的人多 , 使用的公司多 .

1.3、中心控制器

​Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。

​Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)

SpringMVC-LMLPHP

SpringMVC的原理如下图所示:

​当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。

SpringMVC-LMLPHP

1.4、SpringMVC执行原理

图为SpringMVC的一个较完整的流程图,实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现。

简要分析执行流程

  1. DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。

    我们假设请求的url为 : http://localhost:8080/SpringMVC/hello

    如上url拆分成三部分:

    http://localhost:8080服务器域名

    SpringMVC部署在服务器上的web站点

    hello表示控制器

    通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。

  2. HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。

  3. HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。

  4. HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。

  5. HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。

  6. Handler让具体的Controller执行。

  7. Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。

  8. HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。

  9. DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。

  10. 视图解析器将解析的逻辑视图名传给DispatcherServlet。

  11. DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。

  12. 最终视图呈现给用户。

在这里先听一遍原理,不理解没有关系,我们马上来写一个对应的代码实现大家就明白了,如果不明白,那就写10遍,没有笨人,只有懒人!

2.实现SpringMVC(配置版)

  1. 新建一个Moudle,添加Web支持。
  2. 确定导入了SpringMVC的依赖
  3. 配置web.xml,注册DispatcherServlet前端控制器,这是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">

    <!--1.注册前端控制器:DispatcherServlet,这是SpringMVC的核心-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 也可不配置参数,默认加载 /WEB-INF/springmvc-servlet.xml -->
        <!-- DispatcherServlet要绑定一个springmvc配置文件:【servlet-name】- servlet.xml-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <!--启动级别-1-->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- / 匹配接受用户所有的请求;(不包括.jsp)-->
    <!-- /* 匹配接受用户所有的请求;(包括.jsp)-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>
  1. 配置SpringMVC的配置文件:springmvc-servlet.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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--1.添加处理映射器-->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <!--2.添加处理器适配器-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

    <!--3.添加视图解析器:DispatcherServlet给它的ModelAndView
        1.获取了ModelAndView的数据
        2.解析ModelAndView的视图名字
        3.拼接视图名字,找到对应的视图 /WEB-INF/jsp/hello.jsp
        4.将数据渲染到这个视图上
    -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--4.Handler-->
    <bean id="/hello" class="com.dzj.controller.HelloController" />

</beans>
  1. 创建Controller类
package com.dzj.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//注意:我们这里先导入Controller接口
public class HelloController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception{

        //模型和视图
        ModelAndView mv = new ModelAndView();

        //业务代码,假设这里处理了一个业务,返回的结果为result
        String result = "HelloSpringMVC!";
        //封装对象,放在ModelAanView中,Model
        mv.addObject("msg",result);

        //视图跳转封装要跳转的视图,放在ModelAndView中,view
        mv.setViewName("hello"); // 自动拼接成:/WEB-INF/jsp/hello.jsp
        return mv;

    }
}

3.实现SpringMVC(注解版)

第一步:新建一个Moudle,添加web支持,建立包结构 com.dzj.controller

第二步:由于Maven可能存在资源过滤问题,我们将配置完善!

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

第三步:在pom.xml文件引入相关的依赖:主要有Spring框架核心库、SpringMVC、servlet、JSTL等。如果在父依赖中已经引入了,就不需要再引入。注意:在项目结构下添加 lib文件夹,添加 Library Files

<!--导入依赖-->
<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.9</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2.1-b03</version>
        <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

<!--资源过滤-->
<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

第四步:配置web.xml文件

  • 注册DispatcherServlet
  • 关联SpringMVC配置文件
  • 启动级别为1
  • 映射路劲为 “ / ” ,【不要用“ /* ” ,会404】
<!--1.注册前端控制器:DispatcherServlet,这是SpringMVC的核心-->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 也可不配置参数,默认加载 /WEB-INF/springmvc-servlet.xml -->
    <!-- DispatcherServlet要绑定一个springmvc配置文件:【servlet-name】- servlet.xml-->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
    <!--启动级别-1-->
    <load-on-startup>1</load-on-startup>
</servlet>

<!-- / 匹配接受用户所有的请求;(不包括.jsp)-->
<!-- /* 匹配接受用户所有的请求;(包括.jsp)-->
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

第五步:添加Spring MVC配置文件

<?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"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        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 http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
    <context:component-scan base-package="com.dzj.controller"/>
    <!-- 让Spring MVC 不处理静态资源 .css .js  .html .mp3 .mp4-->
    <mvc:default-servlet-handler />
    <!--
        支持mvc注解驱动
        在spring中一般采用@RequestMapping注解来完成映射关系;
        要想使@RequestMapping注解生效;
        必须想上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例,
        这两个实体分别在类级别和方法级别处理;
        而annotation-driver配置帮助我们自动完成上述两个实例的注入。
    -->
    <mvc:annotation-driven/>
    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

第六步:创建controller,HelloController.java

@Controller
public class HelloController {

    @RequestMapping("/hello")
    public String hello(Model model){
        //在模型中添加 msg 和值,可以在jsp中取出并渲染
        model.addAttribute("msg","Hello,SpringMVCAnnotation!");
        return "hello";   // hello 会被视图解析器处理
    }

}

第七步:创建视图层,hello.jsp

第八步:配置Tomcat运行

SpringMVC-LMLPHP

4.注解使用说明

@Controller

//被@Controller注解的类,代表这个类被Spring托管,此类中的方法如果返回值是String类型,
// 并且有具体的页面可以跳转,那么就会被视图解析器解析
@Controller
public class ControllerTest2 {

    @RequestMapping("/test2")
    public String test2(Model model){
        model.addAttribute("msg","ControllerTest2");
        return "test";
    }
}

@RequestMapping

@Controller
@RequestMapping("/c3")  //标注在类上,可理解为第一层级目录
public class ControllerTest3 {
    @RequestMapping("/test2")  //标注在方法上,可理解为第二层级目录
    public String test3(Model model){
        model.addAttribute("msg","ControllerTest3");
        return "test";
    }
}
@Controller
public class ControllerTest3 {

    @RequestMapping("/c3/test2")  //等价于上面的写法
    public String test3(Model model){
        model.addAttribute("msg","ControllerTest3");
        return "test";
    }
}

5.RestFul风格

@Controller
public class RestFulController {

    // 原来的方式 ---> http://localhost:8080/add?a=3&b=7
    // RestFul方式 ---> http://localhost:8080/add/1/2
    // @RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.DELETE)

    @PostMapping("/add/{a}/{b}")
    public String test1(@PathVariable int a,@PathVariable String b, Model model){
        //a,b为前端传递过来的参数
        String res = a + b;
        model.addAttribute("msg","结果为1:" + res);
        return "test";
    }
    @GetMapping("/add/{a}/{b}")
    public String test2(@PathVariable int a,@PathVariable String b, Model model){
        //a,b为前端传递过来的参数
        String res = a + b;
        model.addAttribute("msg","结果为2:" + res);
        return "test";
    }
}

6.SpringMVC的结果跳转方式

1.ModelAndView

设置ModelAndView对象,根据view的名称,和视图解析器跳转到指定的页面

页面 = {视图解析器前缀} + viewName + {视图解析器后缀}

<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!--前缀-->
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <!--后缀-->
    <property name="suffix" value=".jsp"/>
</bean>

对应的Controller类

public class HelloController implements Controller {
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        //模型和视图
        ModelAndView mv = new ModelAndView();
        //业务代码,假设这里处理了一个业务,返回的结果为result
        String result = "HelloSpringMVC!";
        //封装对象,放在ModelAanView中,Model
        mv.addObject("msg",result);
        //视图跳转封装要跳转的视图,放在ModelAndView中,view
        mv.setViewName("hello"); // 自动拼接成:/WEB-INF/jsp/hello.jsp
        return mv;
    }
}

2.ServletAPI

SpringMVC-LMLPHP

@Controller
public class ModelTest1 {
    @RequestMapping("/m1")
    public String test1(HttpServletRequest req, HttpServletResponse resp){
        HttpSession session = req.getSession();
        System.out.println(session.getId());
        return "test";
    }
}

3.SpringMVC

不需要视图解析器

@Controller
public class ModelTest1 {

    @RequestMapping("/m1")
    public String test1(Model model){
        model.addAttribute("msg","ModleTest1");
        //转发,地址栏没有发生变化
        return "/WEB-INF/jsp/test.jsp";  //注意使用全路径
        // 也可写成这样 return "forward:/WEB-INF/jsp/test.jsp";
    }
}
@Controller
public class ModelTest1 {

    @RequestMapping("/m1")
    public String test1(Model model){
        model.addAttribute("msg","ModelTest1");
        //重定向,地址栏会发生变化
        return "redirect:/index.jsp";
    }
}

有视图解析器

默认情况下为转发,在前面加上redirect为重定向

@Controller
public class ModelTest1 {

    @RequestMapping("/m1")
    public String test1(Model model){
        model.addAttribute("msg","ModelTest1");
        //转发
        return "test";
    }
    @RequestMapping("/m2")
    public String test2(Model model){
        model.addAttribute("msg","ModelTest1");
        //重定向
        return "redirect:/index.jsp";
    }
}

7.SpringMVC数据处理

1.处理提交数据

提交的域名称和处理方法的参数一致的情况

@Controller
@RequestMapping("/user")
public class UserController {

    // http://localhost:8080/user/t1?name=dengzhijiang
    @GetMapping("t1")
    public String Test(String name, Model model){
        //1.接受前端数据
        System.out.println("接受前端的数据为:" + name);
        //2.将业务处理后的结果返回给前端,Model
        model.addAttribute("msg",name);
        //3.视图跳转
        return "test";
    }
}

提交的域名称和处理方法的参数不一致的情况

只需在参数前加上 @RequestParma,建议以后不管一不一样都加上

@Controller
@RequestMapping("/user")
public class UserController {

    // http://localhost:8080/user/t1?name=dengzhijiang
    @GetMapping("t1")
    public String Test(@RequestParam("username") String name, Model model){
        //1.接受前端数据
        System.out.println("接受前端的数据为:" + name);
        //2.将业务处理后的结果返回给前端,Model
        model.addAttribute("msg",name);
        //3.视图跳转
        return "test";
    }
}

前端接受的是一个对象

1.接受前端用户传递的参数,判断参数的名字,假设名字直接在方法上,可以直接使用
2.假设传递的是一个对象User,匹配对象User中的字段,如果名字一致则ok,否则匹配不到
3.如果使用对象的话,前端传递的参数名,和对象名属性必须一致,否则就是null
@GetMapping("t2")
public String Test2(User user, Model model){
    // http://localhost:8080/user/t2?id=11&name=dengzhijiang&age=22
    System.out.println(user);
    model.addAttribute("msg",user);
    //3.视图跳转
    return "test";
}

2.数据显示到前端

第一种:通过ModelAndView

public class HelloController implements Controller {
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        //模型和视图
        ModelAndView mv = new ModelAndView();
        //业务代码,假设这里处理了一个业务,返回的结果为result
        String result = "HelloSpringMVC!";
        //封装对象,放在ModelAanView中,Model
        mv.addObject("msg",result);
        //视图跳转封装要跳转的视图,放在ModelAndView中,view
        mv.setViewName("hello"); // 自动拼接成:/WEB-INF/jsp/hello.jsp
        return mv;
    }
}

第二种:通过Model

@Controller
public class HelloController {
    @RequestMapping("/hello")
    public String hello(Model model){
        //在模型中添加 msg 和值,可以在jsp中取出并渲染
        model.addAttribute("msg","Hello,SpringMVCAnnotation!");
        return "hello";   // hello 会被视图解析器处理
    }
}

第三种:通过ModelMap

SpringMVC-LMLPHP

SpringMVC-LMLPHP

3.乱码问题

1.自定义过滤器处理乱码

创建一个过滤器

public class EncodingFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");
        filterChain.doFilter(servletRequest,servletResponse);
    }
    public void destroy() {

    }
}

在web.xml中配置过滤器

<filter>
    <filter-name>encoding</filter-name>
    <filter-class>com.dzj.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
2.可以把Post方法改成Get方法
3.配置SpringMVC的乱码过滤器
<!--2.配置SpringMVC的乱码过滤器-->
<filter>
    <filter-name>encoding</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>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

8.JSON

SpringMVC-LMLPHP

  • JSON是JavaScript对象的字符串表示法,它使用文本表示表示一个JS对象的信息,本质是一个字符串。
var json = {"name":"邓志江","age":3,"sex":"男"}  //这是一个JSON字符串
var obj = {name: '邓志江', age: 3, sex: '男'}   //这是一个Javas对象
  • JSON 和 JavaScript对象的互转
//JavaScript对象转换JSON对象,使用 JSON.stringfy()方法
var json = JSON.stringify(user);
//JSON转换成JavaScript对象,使用 JSON.parse()方法
var obj = JSON.parse(json);

9.Controller返回JSON数据

1.使用 jackson 方式

1.导入依赖

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

2.JSON乱码配置问题

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <constructor-arg value="UTF-8"/>
        </bean>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="failOnEmptyBeans" value="false"/>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

3.实现对象转换为 JSON 字符串

//@Controller
@RestController  //如果在类上标注了@RestController,就不会走视图解析器
public class UserController {
    @RequestMapping("/j1")
    //@ResponseBody  //加了这个注解,就不会走仕途解析器,会直接返回一个字符串,配合@Controller使用
    public String json1() throws JsonProcessingException {
        //jackson里有一个ObjectMapper对象,可以把user对象转换成json字符串
        ObjectMapper mapper = new ObjectMapper();
        User user = new User("邓志江", 22, "男");
        String str = mapper.writeValueAsString(user);// 把user对象转换为JSON字符串
        return str;
    }
}

4.实现集合类型转换为 JSON 字符串

@RequestMapping("/j2")
public String json2() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    List<User> userList = new ArrayList<User>();
    User user1 = new User("邓志江1号", 22, "男");
    User user2 = new User("邓志江2号", 22, "男");
    User user3 = new User("邓志江3号", 22, "男");
    User user4 = new User("邓志江4号", 22, "男");
    User user5 = new User("邓志江5号", 22, "男");

    userList.add(user1);
    userList.add(user2);
    userList.add(user3);
    userList.add(user4);
    userList.add(user5);

    String str = mapper.writeValueAsString(userList);// 把user对象转换为JSON字符串
    return str;
}

5.实现日期类型转换为 JSON 字符串

@RequestMapping("/j3")
public String json3() throws JsonProcessingException {
    Date date = new Date();
    //把时间按照一定的格式显示
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    //ObjectMapper将时间解析后的格式为:timestamp,时间戳
    return new ObjectMapper().writeValueAsString(sdf.format(date));
}

6.源码思想

方法的重载,方法名相同,根据参数的不同调用不同的方法

public static String getJson(Object object){
    return getJson(object,"yyyy-MM-dd HH:mm:ss");
}

public static String getJson(Object object, String dateFormat){
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
    //把时间按照一定的格式显示
    SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
    mapper.setDateFormat(sdf);
    try {
        String str = mapper.writeValueAsString(object);
        return str;
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    return null;
}

2.使用fastjson方式

1.添加 fastjson 依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.78</version>
</dependency>

2.直接使用 JSON.toJSONString()实现转换

@RequestMapping("/j4")
public String json4(){
    List<User> userList = new ArrayList<User>();
    User user1 = new User("邓志江1号", 22, "男");
    User user2 = new User("邓志江2号", 22, "男");
    User user3 = new User("邓志江3号", 22, "男");
    User user4 = new User("邓志江4号", 22, "男");
    User user5 = new User("邓志江5号", 22, "男");
    userList.add(user1);
    userList.add(user2);
    userList.add(user3);
    userList.add(user4);
    userList.add(user5);
    return JSON.toJSONString(userList); //把集合转化为JSON字符串
}

10.SpringMVC:Ajax技术

10.1 简介

SpringMVC-LMLPHP

SpringMVC-LMLPHP

10.2 伪造Ajax

1. 新建一个Moudule

新建一个Moudule:springmvc-06-ajax,导入web支持

2. 编写一个test.html

编写一个test.html 使用 iframe 测试,感受页面无刷新效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>iframe测试体验页面无刷新</title>
    <script type=text/javascript>
        function go() {
            var url = document.getElementById("url").value;
            document.getElementById("iframe1").src=url;
        }
    </script>
</head>
<body>
    <div>
        <p>请输入请求地址:</p>
        <p>
            <input type="text" id="url" value="https://www.baidu.com/" />
            <input type="button" value="提交" onclick="go()"/>
        </p>
    </div>
    <div>
        <iframe id="iframe1" style="width: 100%;height: 500px"></iframe>
    </div>

</body>
</html>

10.3 实现Ajax

1. 下载并导入jQuery
2. 添加静态资源过滤

在applicationContext.xml中添加静态资源过滤

<!--静态资源过滤-->
<mvc:default-servlet-handler/>
3. 编写一个前端页面

实现:当失去焦点的时候,发起一个请求

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
    <%--引入jQuery--%>
    <script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script>
    <script>
      function a() {
          //通过post方式向后台发起请求
          $.post({
              url:"${pageContext.request.contextPath}/a1", //请求地址
              data:{"name":$("#username").val()},  //传递的数据
              success:function (data,status) {    //请求之后的回调函数,返回数据,data接受返回的数据
                  console.log("data="+data);
                  console.log("status="+status);// status 表示请求的状态 200 300 400 500
          })
      }
    </script>
  </head>
  <body>
  <%--失去焦点的时候,发起一个请求--%>
  用户名:<input type="text" id="username" onblur="a()">
  </body>
</html>
4. 后台接受数据返回结果

注意:方法中的参数要和前端ajax中传递的参数名一致

data:{"name":$("#username").val()}
@RestController
public class AjaxController {
    @RequestMapping("/a1")
    public void a1(String name, HttpServletResponse response) throws IOException {
        System.out.println("a=>"+name);
        if("kuangshen".equals(name)){
            response.getWriter().print("true");
        }else {
            response.getWriter().print("false");
        }
    }
}

小结:根据Ajax的地址,后台接收数据,并返回结果,并没有进行重定向或者转发的操作,因此就不会刷新页面,实现了前端页面的局部更新。

SpringMVC-LMLPHP

10.4 Ajax异步加载数据

1. 创建一个User类

注意:使用注解的话,记记得添加 lombok 依赖,并且把jar包添加到 lib 目录中

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
    <scope>provided</scope>
</dependency>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int age;
    private String sex;
}
2. 创建前端页面
body>
    <input id="btn" type="button" value="加载数据" />
    <table>
        <tr>
            <td>名称</td>
            <td>年龄</td>
            <td>性别</td>
        </tr>
        <tbody id="content">

        </tbody>
    </table>
</body>
3. 通过Ajax想后台发起请求
<%-- 引入 jQuery --%>
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script>
<script>
    window.onload=function(){
        $("#btn").click(function () {
            console.log("成功了没??");
            /*
                简写的方式:$.post(url, param[可省略] , success)
             */
            $.post("${pageContext.request.contextPath}/a2",function (data) {
                console.log(data);
                var html = "";
                for (let i = 0; i < data.length; i++) {
                    html += "<tr>" +
                            "<td>" + data[i].name + "</td>" +
                            "<td>" + data[i].age + "</td>" +
                            "<td>" + data[i].sex + "</td>" +
                        "</tr>"
                }
                $("#content").html(html);
            })
        })
    }
</script>
4. 后台实现数据返回到前端
@RequestMapping("/a2")
public List<User> a2(){
    // 创建几个对象,添加到集合中返回到前端
    List<User> userList = new ArrayList<User>();
    userList.add(new User("前端",1,"女"));
    userList.add(new User("后端",2,"男"));
    userList.add(new User("运维",3,"男"));
    return userList;
}

小结:前端通过 Ajax 先向后端发起请求,后台处理请求,并把结果返回到前端,前端把接收到的数据进行处理,显示到页面中。

10.5 Ajax验证用户信息体验

SpringMVC-LMLPHP

1. 创建前端页面login.jsp
<body>
<p>
    用户名:<input type="text" id="userName" onblur="a1()">
    <span id="userId"></span>
</p>
<p>
    密码:<input type="text" id="passWord" onblur="a2()">
    <span id="passWordId"></span>
</p>
</body>
2. 通过Ajax想后台发起请求
<script src="${pageContext.request.contextPath}/statics/js/jquery-3.6.0.js"></script>
<script>
    function a1() {
        $.get({
            url:"${pageContext.request.contextPath}/a3",
            data:{"name":$("#userName").val()},
            success:function (data) {
                console.log(data);
                if(data.toString()==='ok'){
                    $("#userId").css("color","green");
                }else{
                    $("#userId").css("color","red");
                }
                $("#userId").html(data);
            }
        })
    }
    function a2() {
        $.get({
            url:"${pageContext.request.contextPath}/a3",
            data:{"password":$("#passWord").val()},
            success:function (data) {
                console.log(data);
                if(data.toString()==='ok'){
                    $("#passWordId").css("color","green");
                }else{
                    $("#passWordId").css("color","red");
                }
                $("#passWordId").html(data);
            }
        })
    }
</script>
3. 后台实现数据返回前端
@RequestMapping("/a3")
public String a3(String name,String password){
    String msg = "";
    if(name!=null){
        if("admin".equals(name)){
            msg = "ok";
        }else{
            msg = "用户名有误!";
        }
    }
    if(password!=null){
        if("123456".equals(password)){
            msg = "ok";
        }else{
            msg = "密码有误!";
        }
    }
    return msg;
}

11.拦截器

11.1 简单实用拦截器

1.创建一个控制器
@RestController
public class TestController {
    @GetMapping("/t1")
    public String test1(){
        System.out.println("执行成功了");
        return "ok";
    }
}
  1. 创建一个拦截器
public class MyInterceptor implements HandlerInterceptor {

    //return true ,执行下一个拦截器,放行
    //return false ,不执行下一个拦截器
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("*************处理前*************");
        return false;
    }

    //下面两个方法可写可不写,主要用于日志返回
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("*************处理后*************");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("*************清理*************");
    }
}
3. 配置拦截器
<!--拦截器配置-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--包括这个请求下面的所有请求-->
        <mvc:mapping path="/**"/>
        <bean class="com.dzj.config.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

11.2 登录判断验证

1. 入口
<body>
  <h1>
    <a href="${pageContext.request.contextPath}/user/goLogin">登录页面</a>
    <a href="${pageContext.request.contextPath}/user/main">首页</a>
  </h1>
</body>
2. 登录页
<body>
    <%-- 在web-inf下面所有的页面或者资源,只能通过controller或者servlet进行访问--%>
    <h1>登录页面</h1>
    <form action="${pageContext.request.contextPath}/user/login" method="post">
        用户名:<input type="text" name="username">
        密码:<input type="text" name="password">
        <input type="submit" value="提交">
    </form>
</body>
3. 首页
<body>
    <h1>首页</h1>
    <span>${username}</span>
    <p>
        <a href="${pageContext.request.contextPath}/user/goOut">注销</a>
    </p>
</body>
4. 新建控制器
@Controller
@RequestMapping("/user")
public class LoginController {

    @RequestMapping("/main")
    public String main(){
        return "main";
    }

    @RequestMapping("/goLogin")
    public String goLogin(){
        return "Login";
    }

    @RequestMapping("/login")
    public String login(String username, String password, HttpSession session, Model model){
        session.setAttribute("usernameInfo",username);
        model.addAttribute("username",username);
        return "main";
    }

    @RequestMapping("/goOut")
    public String goOut(HttpSession session){
        //移除节点
        session.removeAttribute("usernameInfo");
        return "main";
    }
}
5. 创建拦截器
public class LoginInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        // 放行,判断什么情况下登录

        //登录页面也会放行
        if(request.getRequestURI().contains("goLogin")){
            return true;
        }
        //说明我在提交登录
        if(request.getRequestURI().contains("login")){
            return true;
        }

        //注销登录
        if(request.getRequestURI().contains("goOut")){
            return true;
        }

        //第一次登录也是没有session的
        if((session.getAttribute("userLoginInfo")!=null)&&(request.getRequestURI().contains("main"))){
            return true;
        }
        //判断什么情况下没有登陆
        request.getRequestDispatcher("/WEB-INF/jsp/Login.jsp").forward(request,response);
        return false;
    }
}
6. 配置拦截器
<mvc:interceptor>
    <!--包括user这个请求下面的所有请求-->
    <mvc:mapping path="/user/**"/>
    <bean class="com.dzj.config.LoginInterceptor"/>
</mvc:interceptor>

12.SpringMVC:文件上传和下载

12.1 准备工作

SpringMVC-LMLPHP

SpringMVC-LMLPHP

12.2 文件上传

1. 导入文件上传的jar包

导入文件上传的jar包,commons-fileupload,Maven会自动帮我们导入他的依赖包commons-io

<!-- 文件上传-->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>
<!-- servlet-api导入高版本的 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
2. 配置bean:multipartResolver

注意:这个 bean 的 id 必须为:multipartResolver,否则上传文件会报404的错误!

<bean id="multipartResolver"
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
    <property name="defaultEncoding" value="UTF-8"/>
    <!-- 上传文件大小上限,单位为字节(10MB) -->
    <property name="maxUploadSize" value="10485760"/>
    <property name="maxInMemorySize" value="40960"/>
</bean>
3. 编写前端页面
<body>
    <form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
      <input type="file" name="file"/>
      <input type="submit" value="upload"/>
    </form>
  <a href="${pageContext.request.contextPath}/statics/1.png">下载图片</a>
</body>

四、创建后台控制器

@RestController
public class FileController {

    //@RequestParam("file") 将name=file控件得到的文件封装成ConmmonsMultipartFile对象
    //批量上传CommonsMultipartFile则为数组即可

    /*
        采用file.Transto  来保存上传的文件
     */
    @RequestMapping("/upload")
    public String fileUpload(@RequestParam("file")CommonsMultipartFile file, HttpServletRequest request) throws IOException {

        //上传保存路径设置
        String path = request.getServletContext().getRealPath("/upload");
        File realPath = new File(path);
        if(!realPath.exists()){
            realPath.mkdir();
        }

        //上传文件地址
        System.out.println("上传文件保存地址:"+realPath);
        //通过CommonsMultipartFile的方法直接写文件(注意这个时候)
        file.transferTo(new File(realPath+"/"+file.getOriginalFilename()));
        return "redirect:/index.jsp";

    }
}

12.3 文件下载

文件下载的步骤:

  • 设置 response 响应头
  • 读取文件 -- InputStream
  • 写出文件 -- OutputStream
  • 执行操作
  • 关闭流(先开后关)
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response,HttpServletRequest request) throws Exception {
    //要下载的图片地址
    String path = request.getServletContext().getRealPath("/upload");
    String fileName = "1.png";
    //1.设置response相应头
    response.reset();//设置页面不缓存,清空buffer
    response.setCharacterEncoding("UTF-8");//字符编码
    response.setContentType("multipart/form-data");//二进制传输数据
    //设置响应头
    response.setHeader("Content-Disposition","attachment;fileName="+ URLEncoder.encode(fileName,"UTF-8"));
    File file = new File(path,fileName);
    //2.读取文件--输入流
    InputStream input = new FileInputStream(file);
    //3.写出文件--输出流
    OutputStream out = response.getOutputStream();

    byte[] buff = new byte[1024];
    int index = 0;
    //4.执行 写出操作
    while((index = input.read(buff))!=-1){
        out.write(buff,0,index);
        out.flush();
    }
    out.close();
    input.close();
    return null;
}
直接前端这样也行
<a href="${pageContext.request.contextPath}/statics/1.png">下载图片</a>
09-20 05:07