SpringMVC 详解
1. 回顾 MVC
1.1 什么是 MVC
MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。它不是一种设计模式,而是一种架构模式。它以将业务逻辑、数据、显示分离的方法来组织代码,主要作用是降低了视图与业务逻辑间的双向偶合。
-
Model(模型): 数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或 JavaBean 组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据 Dao) 和服务层(行为 Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
-
View(视图): 负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
-
Controller(控制器): 接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。
最典型的 MVC 就是 JSP + servlet + javabean 的模式。
1.2 Model1 时代
早期的 web 开发中,通常所采用的都是 Model1。在 Model1 中,主要分为两层:视图层和模型层。
-
Model1 的优点:架构简单,比较适合小型项目开发。
-
Model1 的缺点:JSP职责不单一,职责过重,不便于维护。
1.3 Model2 时代
Model2 把一个项目分成三部分,包括视图、控制、模型。
职责解析:
Controller:控制器
- 取得表单数据
- 调用业务逻辑
- 转向指定的页面
Model:模型
- 业务逻辑
- 保存数据的状态
View:视图
- 显示页面
1.4 回顾 Servlet
步骤:
-
新建一个 maven 工程作为父工程,并在 pom.xml 中导入依赖
<!-- 导入依赖 --> <dependencies> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.7</version> </dependency> <!-- servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <!-- jsp --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2.1-b03</version> </dependency> <!-- jstl --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies>
-
在父工程中新建一个 Module,并添加 Web Application 的支持
-
编写一个 Servlet 类,用来处理用户的请求
示例:
HelloServlet.java:
package com.wmwx.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.获得前端参数 String method = req.getParameter("method"); if (method.equals("add")){ req.getSession().setAttribute("msg","执行了add方法"); } if (method.equals("delete")){ req.getSession().setAttribute("msg","执行了delete方法"); } //2.调用业务层(此处暂无) //3.视图转发或重定向 req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
-
编写一个 jsp 页面作为转发的目标
示例:
test.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${msg} </body> </html>
-
在 web.xml 中注册 Servlet
<?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>helloServlet</servlet-name> <servlet-class>com.wmwx.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>helloServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
-
配置 Tomcat,并通过以下地址进行测试
地址:localhost:8080/user?method=add 页面显示:执行了add方法
地址:localhost:8080/user?method=delete 页面显示:执行了delete方法
1.5 MVC 框架要做哪些事情
- 将 url 映射到 java 类或 java 类的方法
- 封装用户提交的数据
- 处理请求——调用相关的业务处理——封装响应数据
- 将响应的数据进行渲染 .jsp/.html 等表示层数据
1.6 常见的 MVC 框架
- 后端:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF 等…
- 前端:vue、angularjs、react、backbone 等…
2. 什么是 SpringMVC
2.1 概述
Spring MVC 是 Spring Framework 的一部分,是基于 Java 实现 MVC 的轻量级 Web 框架。
- 官方文档:SpringMVC 官方文档
Spring MVC 的特点:
- 轻量级,简单易学
- 高效 , 基于请求响应的 MVC 框架
- 与 Spring 兼容性好,无缝结合
- 约定大于配置
- 功能强大:RESTful、数据验证、格式化、本地化、主题等
- 简洁灵活
2.2 中心控制器
-
Spring 的 web 框架围绕 DispatcherServlet 设计。DispatcherServlet 表示前置控制器,是整个 SpringMVC 的控制中心,它的作用是将请求分发到不同的处理器。
-
Spring MVC 框架与许多其他 MVC 框架一样,以请求为驱动,围绕一个中心 Servlet 分派请求及提供其他功能,DispatcherServlet 实质上同样是一个 Servlet (它继承自 HttpServlet 基类)。
-
从 Spring 2.5 开始,使用 Java 5 或者以上版本的用户可以采用基于注解的 controller 声明方式。
2.3 第一个 SpringMVC 程序
步骤:
-
新建一个 Moudle 并添加 Web Application 的支持
-
导入 SpringMVC 的相关依赖(如果父工程中已导入则可以跳过此步骤)
-
配置 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"> <!-- 配置DispatcherServlet:这是SpringMVC的核心,即请求分发器,官方名为前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- DispatcherServlet要绑定spring的配置文件 --> <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> <!-- 在SpringMVC中,对于url-pattern: /:匹配除了jsp页面以外的所有请求 /*:匹配所有请求,包括jsp页面 使用“/*”会导致xxx.jsp.jsp.jsp...的出现,因此使用“/” --> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
-
编写 SpringMVC 的配置文件,并将其命名为 springmvc-servlet.xml(官方推荐:[servletname]-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"> </beans>
-
添加处理映射器
<?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"> <!-- 添加处理映射器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> </beans>
-
添加处理器适配器
<?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"> <!-- 添加处理映射器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!-- 添加处理器适配器 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> </beans>
-
添加视图解析器
<?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"> <!-- 添加处理映射器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!-- 添加处理器适配器 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 添加视图解析器:DispatcherServlet传给它的ModelAndView 执行步骤如下: 1.获取ModelAndView中的数据 2.解析ModelAndView中视图的名字 3.拼接视图名字,找到对应的视图 4.将数据渲染到这个视图上 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean> </beans>
-
编写业务操作控制器
HelloController.java:
package com.wmwx.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 模型和视图 ModelAndView mv = new ModelAndView(); //业务代码 String result = "HelloSpringMVC!"; //封装对象,放在ModelAndView中 mv.addObject("msg", result); //视图跳转 //封装要跳转的视图,放在ModelAndView中 mv.setViewName("hello"); //实际跳转路径: /WEB-INF/jsp/hello.jsp return mv; } }
-
将控制器交给 SpringIOC 容器,注册 bean
<?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"> <!-- 添加处理映射器 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!-- 添加处理器适配器 --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!-- 添加视图解析器:DispatcherServlet传给它的ModelAndView 执行步骤如下: 1.获取ModelAndView中的数据 2.解析ModelAndView中视图的名字 3.拼接视图名字,找到对应的视图 4.将数据渲染到这个视图上 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean> <!-- BeanNameUrlHandlerMapping需要一个Bean --> <bean id="/hello" class="com.wmwx.controller.HelloController" /> </beans>
-
编写要跳转的 jsp 页面
hello.jsp:
<%-- Created by IntelliJ IDEA. User: Administrator Date: 2021/5/22 Time: 23:48 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${msg} </body> </html>
-
启动 Tomcat 进行测试
-
如果遇到访问出现404的问题,可以依次排查:
- 查看控制台输出,看一下是不是缺少了什么 jar 包
- 如果 jar 包已存在,仍显示无法输出,就在 IDEA 的项目发布中,添加 lib 依赖
- 重启 Tomcat 即可解决
2.4 SpringMVC 运行原理
SpringMVC 的运行原理如下图所示(图片来自狂神说微信公众号):
运行流程依次如下(序号对应图中箭头的编号):
-
DispatcherServlet 表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet 接收请求并拦截请求。
我们假设请求的 url 为 : http://localhost:8080/SpringMVC/hello
则如上 url 可拆分成三部分:
-
http://localhost:8080:服务器域名
-
SpringMVC:部署在服务器上的 web 站点
-
hello:控制器
通过分析,如上 url 表示为:请求位于服务器 localhost:8080 上的 SpringMVC 站点的 hello 控制器。
-
-
HandlerMapping 为处理器映射。DispatcherServlet 调用 HandlerMapping,HandlerMapping 根据请求 url 查找 Handler。
-
HandlerExecution 表示具体的 Handler,其主要作用是根据 url 查找控制器,如上 url 被查找控制器为 hello。
-
HandlerExecution 将解析后的信息传递给 DispatcherServlet,如解析控制器映射等。
-
HandlerAdapter 表示处理器适配器,其按照特定的规则去执行 Handler。
-
Handler 让具体的 Controller 执行。
-
Controller 将具体的执行信息返回给 HandlerAdapter,如 ModelAndView。
-
HandlerAdapter 将视图逻辑名或模型传递给 DispatcherServlet。
-
DispatcherServlet 调用视图解析器(ViewResolver)来解析 HandlerAdapter 传递的逻辑视图名。
-
视图解析器将解析的逻辑视图名传给 DispatcherServlet。
-
DispatcherServlet 根据视图解析器解析的视图结果,调用具体的视图。
-
最终视图呈现给用户。
2.5 使用注解开发
虽然 2.3 中的列出的步骤十分详细,逻辑也十分清晰,但在一般的开发中不会这么去做。更多地,我们还是会去使用注解来实现。
具体的实现步骤如下:
-
新建一个 Moudle 并添加 Web Application 的支持
-
由于 Maven 可能存在资源过滤的问题,需将配置完善
pom.xml:
<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>
-
导入 SpringMVC 的相关依赖(如果父工程中已导入则可以跳过此步骤)
-
配置 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"> <!-- 配置DispatcherServlet:这是SpringMVC的核心,即请求分发器,官方名为前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- DispatcherServlet要绑定spring的配置文件 --> <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> <!-- 在SpringMVC中,对于url-pattern: /:匹配除了jsp页面以外的所有请求 /*:匹配所有请求,包括jsp页面 使用“/*”会导致xxx.jsp.jsp.jsp...的出现,因此使用“/” --> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
-
编写 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" 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.wmwx.controller"/> <!-- 让Spring MVC不处理静态资源 --> <mvc:default-servlet-handler /> <!-- 支持mvc注解驱动 在spring中一般采用@RequestMapping注解来完成映射关系 要想使@RequestMapping注解生效 必须向上下文中注册DefaultAnnotationHandlerMapping 和一个AnnotationMethodHandlerAdapter实例 这两个实例分别在类级别和方法级别处理。 而annotation-driven配置帮助我们自动完成上述两个实例的注入。 --> <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:
package com.wmwx.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HelloController { @RequestMapping("/hello") //拼接后的地址:localhost:8080/hello public String hello(Model model){ //封装数据 model.addAttribute("msg", "HelloSpringMVC!"); //会被视图解析器解析 return "hello"; //路径:/WEB-INF/jsp/hello.jsp } }
-
创建视图层
hello.jsp:
<%-- Created by IntelliJ IDEA. User: Administrator Date: 2021/5/23 Time: 8:21 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${msg} </body> </html>
-
配置 Tomcat 并启动测试
2.6 小结
使用 springMVC 必须配置的三大件:
- 处理器映射器
- 处理器适配器
- 视图解析器
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的 xml 配置
3. Controller 配置总结
3.1 控制器(Controller)
- 控制器负责提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。
- 控制器负责解析用户的请求并将其转换为一个模型。
- 在 Spring MVC 中一个控制器类可以包含多个方法
- 在 Spring MVC 中,对于 Controller 的配置方式有很多种
3.2 接口定义
Controller 是一个接口,在 org.springframework.web.servlet.mvc 包下,接口中只有一个方法:
@FunctionalInterface
public interface Controller {
@Nullable
ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}
因此,如果我们希望使用一个类来实现这个接口,那么只需要实现该方法即可。
步骤如下:
-
新建一个 Moudle 并添加 Web Application 的支持
-
导入 SpringMVC 的相关依赖(如果父工程中已导入则可以跳过此步骤)
-
配置 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"> <!-- 配置DispatcherServlet:这是SpringMVC的核心,即请求分发器,官方名为前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- DispatcherServlet要绑定spring的配置文件 --> <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> <!-- 在SpringMVC中,对于url-pattern: /:匹配除了jsp页面以外的所有请求 /*:匹配所有请求,包括jsp页面 使用“/*”会导致xxx.jsp.jsp.jsp...的出现,因此使用“/” --> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
-
编写 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" 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"> <!-- 支持mvc注解驱动 在spring中一般采用@RequestMapping注解来完成映射关系 要想使@RequestMapping注解生效 必须向上下文中注册DefaultAnnotationHandlerMapping 和一个AnnotationMethodHandlerAdapter实例 这两个实例分别在类级别和方法级别处理。 而annotation-driven配置帮助我们自动完成上述两个实例的注入。 --> <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 的类
package com.wmwx.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 ControllerTest1 implements Controller { public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { ModelAndView mv = new ModelAndView(); mv.addObject("msg", "ControllerTest1"); mv.setViewName("test"); return mv; } }
-
在 spring 配置文件中注册 bean
<?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"> <!-- 支持mvc注解驱动 在spring中一般采用@RequestMapping注解来完成映射关系 要想使@RequestMapping注解生效 必须向上下文中注册DefaultAnnotationHandlerMapping 和一个AnnotationMethodHandlerAdapter实例 这两个实例分别在类级别和方法级别处理。 而annotation-driven配置帮助我们自动完成上述两个实例的注入。 --> <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> <bean class="com.wmwx.controller.ControllerTest1" id="/test1" /> </beans>
-
编写待跳转的页面
<%-- Created by IntelliJ IDEA. User: Administrator Date: 2021/5/23 Time: 9:03 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${msg} </body> </html>
-
启动 Tomcat 测试
在地址栏中输入:localhost:8080/test1 页面中显示:ControllerTest1
说明:
- 实现接口 Controller 定义控制器是较老的办法。它的缺点是:一个控制器中只有一个方法,如果要多个方法则需要定义多个 Controller。因此,使用接口定义的方式比较麻烦,不推荐使用。
3.3 注解定义
@Controller 注解类型用于声明 Spring 类的实例是一个控制器。Spring 可以使用扫描机制来找到应用程序中所有基于注解的控制器类。为了保证 Spring 能找到你的控制器,需要在配置文件中声明组件扫描。
<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="com.wmwx.controller"/>
<!-- 让Spring MVC不处理静态资源 -->
<mvc:default-servlet-handler />
在 3.2 的代码基础上,将这段代码添加进 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"
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.wmwx.controller"/>
<!-- 让Spring MVC不处理静态资源 -->
<mvc:default-servlet-handler />
<!--
支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-->
<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>
<bean class="com.wmwx.controller.ControllerTest1" id="/test1" />
</beans>
接着,增加一个 ControllerTest2.java,并使用 @Controller 注解:
package com.wmwx.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
//@Controller代表这个类会被Spring接管
//被其注解的类,如果有返回值为String的方法,那么将自动被视图解析器解析
@Controller
public class ControllerTest2 {
@RequestMapping("/test2")
public String test1(Model model){
model.addAttribute("msg", "ControllerTest2");
return "test";
}
@RequestMapping("/test3")
public String test2(Model model){
model.addAttribute("msg", "ControllerTest2 - test2");
return "test";
}
}
启动 Tomcat 进行测试,可以看到以下结果:
在地址栏中输入:localhost:8080/test2
页面显示:ControllerTest2
在地址栏中输入:localhost:8080/test3
页面显示:ControllerTest2 - test2
可以发现,在该类中,我们定义了两个方法,分别发送了两个请求。这两个请求都可以指向一个视图,但是页面结果的结果是不一样的。由此可以看出,视图是被复用的,而控制器与视图之间是弱耦合关系。
因此,注解定义是最常用的方式。
3.4 @RequestMapping
@RequestMapping 注解用于映射 url 到控制器类或一个特定的处理程序方法。即,它既可以用于类上,也可以用于方法上。若用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。
示例:
在 3.3 的代码基础上,新建一个 ControllerTest3.java:
package com.wmwx.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/ct3")
public class ControllerTest3 {
@RequestMapping("/test1")
public String test1(Model model){
model.addAttribute("msg", "ControllerTest3");
return "test";
}
}
启动 Tomcat 测试,可以看到如下结果:
地址栏输入:localhost:8080/ct3/test1
页面显示:ControllerTest3
3.5 Restful 风格
3.5.1 概念
Restful 就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
Restful 具有资源操作的功能:
-
资源:互联网所有的事物都可以被抽象为资源
-
资源操作:POST、DELETE、PUT、GET,分别对应添加、删除、修改、查询,使用不同方法对资源进行操作。
3.5.2 传统方式操作资源
在传统方式中,我们需要通过不同的参数来实现不同的效果。这种方式的方法单一,只有 POST 和 GET。
示例:
-
http://127.0.0.1/item/queryItem.action?id=1:查询,GET
-
http://127.0.0.1/item/saveItem.action:增加,POST
-
http://127.0.0.1/item/updateItem.action:修改,POST
-
http://127.0.0.1/item/deleteItem.action?id=1:删除,GET 或 POST
3.5.3 Restful 风格操作资源
使用 Restful 风格,可以通过不同的请求方式来实现不同的效果。
示例:
-
http://127.0.0.1/item/1:查询,GET
-
http://127.0.0.1/item:新增,POST
-
http://127.0.0.1/item:更新,PUT
-
http://127.0.0.1/item/1:删除,DELETE
3.5.4 测试
在 3.4 的基础上,新建一个 RestfulController.java,并使用注解定义的方式配置 Controller:
package com.wmwx.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RestfulController {
//映射访问路径
//使用@PathVariable注解,让方法参数的值对应绑定到一个URI模板变量上
@RequestMapping("/commit/{a}/{b}")
public String restfulTest1(@PathVariable int a, @PathVariable int b, Model model){
//对地址栏里的参数做加法运算
model.addAttribute("msg", a+b);
return "test";
}
}
启动 Tomcat 测试,可以看到如下结果:
地址栏输入:localhost:8080/commit/2/3
页面显示:5
3.5.5 指定请求类型
使用 method 属性指定请求类型,可以收窄请求范围。指定请求谓词的类型如 GET、POST、HEAD、OPTIONS、PUT、PATCH、DELETE、TRACE 等。
示例:
package com.wmwx.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class RestfulController {
//映射访问路径
//使用@PathVariable注解,让方法参数的值对应绑定到一个URI模板变量上
//限定POST请求才会访问
@RequestMapping(value="/commit/{a}/{b}", method={RequestMethod.POST})
public String restfulTest1(@PathVariable int a, @PathVariable int b, Model model){
model.addAttribute("msg", a+b);
return "test";
}
}
通过 method 属性将请求类型限制为 POST,启动 Tomcat 测试,可以看到如下结果:
地址栏输入:localhost:8080/commit/2/3
页面显示:HTTP状态 405 - 方法不允许
注意:所有的地址栏请求默认都是 HTTP GET 类型的。
将 method 属性改为 GET:
package com.wmwx.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class RestfulController {
//映射访问路径
//使用@PathVariable注解,让方法参数的值对应绑定到一个URI模板变量上
//限定GET请求才会访问
@RequestMapping(value="/commit/{a}/{b}", method={RequestMethod.GET})
public String restfulTest1(@PathVariable int a, @PathVariable int b, Model model){
model.addAttribute("msg", a+b);
return "test";
}
}
再次启动 Tomcat 测试,可以看到如下结果:
地址栏输入:localhost:8080/commit/2/3
页面显示:5
除此之外,方法级别的注解还有如下几个变体,它们所扮演的是 @RequestMapping(method =RequestMethod.XXX) 的一个快捷方式:
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
则前面的代码可以等价于如下:
package com.wmwx.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class RestfulController {
//映射访问路径
//使用@PathVariable注解,让方法参数的值对应绑定到一个URI模板变量上
//限定GET请求才会访问
//等价于 @RequestMapping(value="/commit/{a}/{b}", method={RequestMethod.GET})
@RequestMapping("/commit/{a}/{b}")
@GetMapping
public String restfulTest1(@PathVariable int a, @PathVariable int b, Model model){
model.addAttribute("msg", a+b);
return "test";
}
}
4. 数据处理
4.1 处理提交的数据
处理从前端提交的数据,总共有三种情况,分别为:
-
提交的域名称和处理方法的参数名一致
示例:
UserController.java :
package com.wmwx.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class UserController { @RequestMapping("/user/t1") public String test1(String name, Model model){ //1.接收参数(已接收) //2.传回前端 model.addAttribute("msg", name); //3.视图跳转 return "test"; } }
启动 Tomcat 测试,可以看到如下结果:
输入地址:http://localhost:8080/user?name=wmwx 页面显示:wmwx
-
提交的域名称和处理方法的参数名不一致
示例:
UserController.java:
package com.wmwx.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class UserController { @RequestMapping("user/t2") //使用注解@RequestParam public String test2(@RequestParam("username") String name, Model model){ //1.接收参数(已接收) //2.传回前端 model.addAttribute("msg", name); //3.视图跳转 return "test"; } }
启动 Tomcat 测试,可以看到如下结果:
输入地址:http://localhost:8080/user/t2?username=wmwx 页面显示:wmwx
事实上,无论前端传来的参数与方法中的参数名是否相同,都推荐加上 @RequestParam 注解来与后端传来的参数作区分。
-
提交的是一个对象
示例:
User.java:
package com.wmwx.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private int age; }
UserController.java:
package com.wmwx.controller; import com.wmwx.pojo.User; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class UserController { @RequestMapping("user/t3") public String test3(User user, Model model){ //1.接收参数(已接收) //2.传回前端 model.addAttribute("msg", user.toString()); //3.视图跳转 return "test"; } }
启动 Tomcat 测试,可以看到如下结果:
输入地址:http://localhost:8080/user/t3?id=1&name=snow&age=23 页面显示:User(id=1, name=snow, age=23)
说明:如果使用对象传参的方式,就要求前端传递的参数名和对象的属性名必须一致,否则就会传 null。
4.2 数据显示到前端
将数据显示到前端,总共有三种方式,分别为:
-
通过 ModelAndView
package com.wmwx.controller; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ControllerTest1 implements Controller { public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { ModelAndView mv = new ModelAndView(); mv.addObject("msg", "ControllerTest1"); mv.setViewName("test"); return mv; } }
-
通过 ModelMap
package com.wmwx.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class ModelTestController { @RequestMapping("/mt/t1") public String test1(ModelMap map){ map.addAttribute("msg", "ModelMap"); return "test"; } }
-
通过 Model
package com.wmwx.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class ModelTestController { @RequestMapping("/mt/t2") public String test2(Model model){ model.addAttribute("msg", "ModelMap"); return "test"; } }
这三种方式的区别为:
- Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于 Model 对象的操作和理解
- ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性
- ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转
4.3 乱码问题
乱码问题是在我们的开发中十分常见。比如,当用户在表单中输入中文后,提交的数据就有可能出现乱码。好在 SpringMVC 给我们提供了一个过滤器,可以在 web.xml 中直接配置使用:
<!-- 配置spring的过滤器解决乱码问题 -->
<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>
只需将这一段代码粘贴在 web.xml 中,乱码问题便迎刃而解。
5. JSON
5.1 什么是 JSON
JSON(JavaScript Object Notation,JS 对象标记)是一种轻量级的数据交换格式,目前使用特别广泛。它采用完全独立于编程语言的文本格式来存储和表示数据,易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。其简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
在 JavaScript 语言中,一切都是对象。因此,任何 JavaScript 支持的类型都可以通过 JSON 来表示。例如,字符串、数字、对象、数组等。其语法格式如下:
- 对象表示为键值对,数据由逗号分隔
- 花括号为对象,方括号保存数组,可在数组中存放多个对象
示例:
{"name": "刘季恒"}
{"age": "18"}
{"sex": "男"}
5.2 JSON 和 JS对象
-
JSON --> JS 对象
let obj = JSON.parse('{"a": "Hello", "b": "World"}');
-
JS 对象 --> JSON
let json = JSON.stringify({a: 'Hello', b: 'World'});
5.3 Jackson
5.3.1 使用 Jackson
JSON 解析工具有很多,其中 Jackson 算是目前比较好用的一个了。如果想要使用 Jackson,需要导入它的 jar 包:
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
测试步骤:
-
配置 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"> <!-- 配置DispatcherServlet:这是SpringMVC的核心,即请求分发器,官方名为前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- DispatcherServlet要绑定spring的配置文件 --> <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> <!-- 在SpringMVC中,对于url-pattern: /:匹配除了jsp页面以外的所有请求 /*:匹配所有请求,包括jsp页面 使用“/*”会导致xxx.jsp.jsp.jsp...的出现,因此使用“/” --> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 配置spring的过滤器解决乱码问题 --> <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> </web-app>
-
配置 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" 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.wmwx.controller"/> <!-- 让Spring MVC不处理静态资源 --> <mvc:default-servlet-handler /> <!-- 支持mvc注解驱动 在spring中一般采用@RequestMapping注解来完成映射关系 要想使@RequestMapping注解生效 必须向上下文中注册DefaultAnnotationHandlerMapping 和一个AnnotationMethodHandlerAdapter实例 这两个实例分别在类级别和方法级别处理。 而annotation-driven配置帮助我们自动完成上述两个实例的注入。 --> <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>
-
编写实体类
User.java:
package com.wmwx.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private int age; }
-
编写 Controller,并改用 @RestController 注解
UserController.java:
package com.wmwx.controller; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.wmwx.pojo.User; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; //添加了这个注解不会走视图解析器,而是直接返回字符串 //若要前后端分离,一般都会使用这个注解 @RestController public class UserController { @RequestMapping("/j1") public String json1() throws JsonProcessingException { //jackson.objectMapper ObjectMapper mapper = new ObjectMapper(); User user = new User(1, "刘季恒", 18); //这个方法将对象转化为字符串,需要抛出异常 String userString = mapper.writeValueAsString(user); return userString; } }
-
配置 Tomcat 并启动测试
输入地址:http://localhost:8080/j1 页面显示:{"id":1,"name":"???","age":18}
5.3.2 解决乱码问题
虽然生成的 JSON 字符串已经成功显示,但是其中的中文部分还是出现了乱码。这个问题又该如何解决呢?
Spring 提供了一种统一配置的方式,可以自动处理 Jackson 的乱码问题:
<!-- 解决Jackson的乱码问题 -->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<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>
将这一段添加在 springmvc-servlet.xml 中,乱码问题就解决了!
配置 Tomcat 并启动测试
输入地址:http://localhost:8080/j1
页面显示:{"id":1,"name":"刘季恒","age":18}
5.3.3 集合的输出
在 5.3.2 的代码基础上,向 UserController.java 中新增一个方法:
@RequestMapping("/j2")
public String json2() throws JsonProcessingException {
//创建多个对象
User user1 = new User(1, "刘季恒", 18);
User user2 = new User(2, "周松雅", 18);
User user3 = new User(3, "吕沁", 23);
User user4 = new User(4, "张鹏", 35);
User user5 = new User(5, "余征", 20);
//创建集合
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
userList.add(user5);
//将集合转化为字符串,需要抛出异常
return new ObjectMapper().writeValueAsString(userList);
}
配置 Tomcat 并启动测试
输入地址:http://localhost:8080/j2
页面显示:[{"id":1,"name":"刘季恒","age":18},{"id":2,"name":"周松雅","age":18},{"id":3,"name":"吕沁","age":23},{"id":4,"name":"张鹏","age":35},{"id":5,"name":"余征","age":20}]
5.3.4 时间格式的输出
在 5.3.3 的代码基础上,向 UserController.java 中新增一个方法:
@RequestMapping("/j3")
public String json3() throws JsonProcessingException {
return new ObjectMapper().writeValueAsString(new Date());
}
配置 Tomcat 并启动测试:
输入地址:http://localhost:8080/j3
页面显示:1621779713335
刷新页面,可以看到显示的变化:
第一次刷新:1621779837915
第二次刷新:1621779843240
第三次刷新:1621779848888
... ...
不难看出,jackson 解析 Date 对象后的默认格式为 Timestamp,即时间戳格式。
如果要将时间戳格式转换成我们想要的格式,有两种方式可以解决:
-
纯粹使用 SimpleDateFormat:
@RequestMapping("/j3") public String json3() throws JsonProcessingException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return new ObjectMapper().writeValueAsString(sdf.format(new Date())); }
配置 Tomcat 并启动测试:
输入地址:http://localhost:8080/j3 页面显示:"2021-05-23 22:29:27"
-
搭配 ObjectMapper:
@RequestMapping("/j3") public String json3() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); //配置ObjectMapper不使用时间戳 mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); mapper.setDateFormat(sdf); return mapper.writeValueAsString(new Date()); }
配置 Tomcat 并启动测试:
输入地址:http://localhost:8080/j3 页面显示:"2021-05-23 22:35:09"
5.3.5 封装成工具类
日期的格式转换是一个经常使用的功能,最好封装为一个工具类去调用。
示例:
JsonUtils.java:
package com.wmwx.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.text.SimpleDateFormat;
public class JsonUtils {
//方法重载无需再写一遍内容,只需调用另一个方法即可
public static String getJson(Object object) {
return getJson(object, "yyyy-MM-dd HH:mm:ss");
}
public static String getJson(Object object, String sdfString) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
SimpleDateFormat sdf = new SimpleDateFormat(sdfString);
mapper.setDateFormat(sdf);
try {
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
这样以来,5.3.4 中的代码就可以改成如下方式:
@RequestMapping("/j3")
public String json3() {
//调用编写好的工具类
return JsonUtils.getJson(new Date());
}
配置 Tomcat 并启动测试:
输入地址:http://localhost:8080/j3
页面显示:"2021-05-23 22:47:12"
由此可见,现在只需一行代码,就可以做到日期格式的转换。
由于我们在工具类中定义了方法的重载,故可以将 5.3.1、5.3.3 中的代码一并改造:
package com.wmwx.controller;
import com.wmwx.pojo.User;
import com.wmwx.utils.JsonUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
//添加了这个注解不会走视图解析器,而是直接返回字符串
//若要前后端分离,一般都会使用这个注解
@RestController
public class UserController {
@RequestMapping("/j1")
public String json1() {
User user = new User(1, "刘季恒", 18);
return JsonUtils.getJson(user);
}
@RequestMapping("/j2")
public String json2() {
//创建多个对象
User user1 = new User(1, "刘季恒", 18);
User user2 = new User(2, "周松雅", 18);
User user3 = new User(3, "吕沁", 23);
User user4 = new User(4, "张鹏", 35);
User user5 = new User(5, "余征", 20);
//创建集合
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
userList.add(user5);
//将集合转化为字符串,需要抛出异常
return JsonUtils.getJson(userList);
}
@RequestMapping("/j3")
public String json3() {
//调用编写好的工具类
return JsonUtils.getJson(new Date());
}
}
5.4 Fastjson
fastjson.jar 是阿里开发的一款专门用于 Java 开发的包,可以方便地实现 json 字符串与 JavaBean 对象的转换,以及 JavaBean 对象与 json 字符串的转换。
要想使用 fastjson,需要先导入 jar 包:
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
接着,我们在 5.3.5 的代码基础上,向 UserController.java 中新增一个方法:
@RequestMapping("/j4")
public String json4() {
User user1 = new User(1, "刘季恒", 18);
User user2 = new User(2, "周松雅", 18);
User user3 = new User(3, "吕沁", 23);
User user4 = new User(4, "张鹏", 35);
User user5 = new User(5, "余征", 20);
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
userList.add(user5);
System.out.println("*******Java对象 转 JSON字符串*******");
String str1 = JSON.toJSONString(userList);
System.out.println("JSON.toJSONString(userList)==>"+str1);
String str2 = JSON.toJSONString(user1);
System.out.println("JSON.toJSONString(user1)==>"+str2);
System.out.println("\n****** JSON字符串 转 Java对象*******");
User jp_user1=JSON.parseObject(str2,User.class);
System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);
System.out.println("\n****** Java对象 转 JSON对象 ******");
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
System.out.println("(JSONObject) JSON.toJSON(user2).getString(\"name\")==>"+jsonObject1.getString("name"));
System.out.println("\n****** JSON对象 转 Java对象 ******");
User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);
return null;
}
输出结果:
*******Java对象 转 JSON字符串*******
JSON.toJSONString(userList)==>[{"age":18,"id":1,"name":"刘季恒"},{"age":18,"id":2,"name":"周松雅"},{"age":23,"id":3,"name":"吕沁"},{"age":35,"id":4,"name":"张鹏"},{"age":20,"id":5,"name":"余征"}]
JSON.toJSONString(user1)==>{"age":18,"id":1,"name":"刘季恒"}
****** JSON字符串 转 Java对象*******
JSON.parseObject(str2,User.class)==>User(id=1, name=刘季恒, age=18)
****** Java对象 转 JSON对象 ******
(JSONObject) JSON.toJSON(user2).getString("name")==>周松雅
****** JSON对象 转 Java对象 ******
JSON.toJavaObject(jsonObject1, User.class)==>User(id=2, name=周松雅, age=18)