什么是MVC?
- MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
- 是将业务逻辑、数据、显示分离的方法来组织代码。
- MVC主要作用是降低了视图与业务逻辑间的双向偶合。
- MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。
最典型的MVC就是JSP + servlet + javabean的模式。
Model1时代
- 在web早期的开发中,通常采用的都是Model1。
- Model1中,主要分为两层,视图层和模型层。
Model1优点:架构简单,比较适合小型项目开发;
Model1缺点:JSP职责不单一,职责过重,不便于维护;
Model2时代
Model2把一个项目分成三部分,包括视图、控制、模型。
- 用户发请求
- Servlet接收请求数据,并调用对应的业务逻辑方法
- 业务处理完毕,返回更新后的数据给servlet
- servlet转向到JSP,由JSP来渲染页面
- 响应给前端更新后的页面
职责分析:
Controller:控制器
- 取得表单数据
- 调用业务逻辑
- 转向指定的页面
Model:模型
- 业务逻辑
- 保存数据的状态
View:视图
- 显示页面
Model2这样不仅提高的代码的复用率与项目的扩展性,且大大降低了项目的维护成本。Model 1模式的实现比较简单,适用于快速开发小规模项目,Model1中JSP页面身兼View和Controller两种角色,将控制逻辑和表现逻辑混杂在一起,从而导致代码的重用性非常低,增加了应用的扩展性和维护的难度。Model2消除了Model1的缺点。
回顾Servlet
新建一个Maven工程当做==父工程==!pom依赖!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>建立一个==Moudle==:springmvc-01-servlet , 添加Web app的支持!(选中module,点击鼠标右键,选择“Add Framework Support…”,再选择“Web Application”,确认即可)
编写一个Servlet类,用来处理用户的请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30package com.kuang.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//实现Servlet接口
public class HelloServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//取得参数
String method = req.getParameter("method");
if (method.equals("add")){
req.getSession().setAttribute("msg","执行了add方法");
}
if (method.equals("delete")){
req.getSession().setAttribute("msg","执行了delete方法");
}
//业务逻辑
//视图跳转
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);//转发
// resp.sendRedirect();//重定向
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}编写test.jsp,在WEB-INF目录下新建一个jsp的文件夹,新建test.jsp
1
2
3
4
5
6
7
8
9<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>在web.xml中注册Servlet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<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>hello</servlet-name>
<servlet-class>com.kuang.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>配置Tomcat,并启动测试
测试
localhost:8080/hello?method=add
localhost:8080/hello?method=delete
MVC框架要做哪些事情
- 将url映射到java类或java类的方法 .
- 封装用户提交的数据 .
- 处理请求–调用相关的业务处理–封装响应数据 .
- 将响应的数据进行渲染 . jsp / html 等表示层数据 .
说明:
常见的服务器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;常见前端MVC框架:vue、angularjs、react、backbone;由MVC演化出了另外一些模式如:MVP、MVVM 等等…
什么是SpringMVC
概述
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的特点:
- 轻量级,简单易学
- 高效 , 基于请求响应的MVC框架
- 与Spring兼容性好,无缝结合
- 约定优于配置
- 功能强大:RESTful、数据验证、格式化、本地化、主题等
- 简洁灵活
Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计。
DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解形式进行开发,十分简洁;
正因为SpringMVC好 , 简单 , 便捷 , 易学 , 天生和Spring无缝集成(使用SpringIoC和Aop) , 使用约定优于配置 . 能够进行简单的junit测试 . 支持Restful风格 .异常处理 , 本地化 , 国际化 , 数据验证 , 类型转换 , 拦截器 等等…所以我们要学习 .
最重要的一点还是用的人多 , 使用的公司多 .
中心控制器
Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。
Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)。
SpringMVC的原理如下图所示:
当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。
SpringMVC执行原理
图为SpringMVC的一个较完整的流程图,实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现。
简要分析执行流程
DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
我们假设请求的url为 : http://localhost:8080/SpringMVC/hello
如上url拆分成三部分:
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根据视图解析器解析的视图结果,调用具体的视图。
最终视图呈现给用户。
在这里先听一遍原理,不理解没有关系,我们马上来写一个对应的代码实现大家就明白了,如果不明白,那就写10遍,没有笨人,只有懒人!
创建springmvc程序
控制器Controller
- 控制器负责提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。
- 控制器负责解析用户的请求并将其转换为一个模型。
- 在Spring MVC中一个控制器类可以包含多个方法
- 在Spring MVC中,对于Controller的配置方式有很多种
实现Controller接口
Controller是一个接口,在org.springframework.web.servlet.mvc包下,接口中只有一个方法;
1 |
//实现该接口的类获得控制器功能 |
案例:见下边的SpringMVC“配置版”例子。
小结:
- 实现接口Controller定义控制器是较老的办法
- 缺点是:一个控制器中只有一个方法,如果要多个方法则需要定义多个Controller;定义的方式比较麻烦;
使用注解@Controller
==@Controller==注解用于声明当前类是一个控制器。
==@RequestMapping==注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
案例:见下边的SpringMVC“注解版”例子。
小结:注解方式是平时使用的最多的方式!
配置版
创建项目
1、新建一个Moudle名为“springmvc-02-hellomvc”(普通maven项目) , 添加web的支持!(选中module,点击鼠标右键,选择“Add Framework Support…”,再选择“Web Application”,确认即可)
依赖
2、确定导入了SpringMVC 的依赖!(我们在父工程中已经导入需要的依赖)
1 |
<dependency> |
web.xml
3、在web.xml文件中(Javaweb的配置文件) , 配置DispatcherServlet。这个是SpringMVC的核心:请求分发器,前端控制器
1 |
|
/ 和 /* 的区别:
- < url-pattern > / </ url-pattern > 不会匹配到.jsp, 只针对我们编写的请求;即:.jsp 不会进入spring的 DispatcherServlet类 。
- < url-pattern > /* </ url-pattern > 会匹配 *.jsp,会出现返回 jsp视图 时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。
注意web.xml版本问题,要最新版!(当前项目使用的是4.0)
- 注册DispatcherServlet
- 关联SpringMVC的配置文件
- 启动级别为1
- 映射路径为 / 【不要用/*,会404】
SpringMVC配置文件
4、编写SpringMVC的配置文件!名称为springmvc-servlet.xml,放在resources文件夹下(名字可以任意起,但最好还是照着命名规范来好一点)
1 |
|
5、添加 处理器映射器(HandlerMapping)。处理器映射器,根据URL查找处理器(Controller)。URL对应处理器注册到Spring的IOC容器时设置的标识符(id、name)。
1 |
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> |
6、添加 处理器适配器(HandlerAdapter)。查找到处理器后交由处理器适配器处理。
1 |
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> |
7、添加 视图解析器(ViewResolver)。调用处理器Controller后返回的数据交由视图解析器处理。
1 |
<!--视图解析器:模版引擎Thymeleaf Freemarker等。DispatcherServlet传递ModelAndView过来--> |
注意,这里的5、6、7步甚至都可以不配置,因为SpringMVC已经配置好了,这里只是为了更好的理解SpringMVC的执行原理才重复进行配置。(若不要第7步,则返回的视图名要填完整的路径。例如:/WEB-INF/jsp/hello.jsp)
Controller
8、编写Controller,要么实现Controller接口,要么增加注解;需要返回一个ModelAndView,封装数据和视图;
我们要实现的业务是:当用户访问路径“/hello”后返回字符串“HelloSpringMVC”(模型-数据)和页面“hello.jsp“(视图-页面),字符串将被渲染到hello.jsp中,然后将该页面返回给用户。(ModelAndView实现页面转发)
1 |
package com.kuang.controller; |
9、将自己的类交给SpringIOC容器,在SpringMVC的配置文件中注册bean,标识符(name/id)对应请求路径,class对应处理请求的类(也可以理解为配置Controller的请求路径)。
1 |
<!--Handler。HandlerMapping 处理器映射器,根据URL查找映射器(即我们写的Controller类,在Spring中要注册bean到IOC容器中)--> |
页面
10、写要跳转的jsp页面,显示ModelandView存放的数据,以及我们的正常页面;文件名为hello,对应上Controller中写的视图名。
在WEB-INF/jsp目录中创建hello.jsp , 视图可以直接取出并展示从Controller带回的信息;可以通过EL表示取出Model中存放的值,或者对象;
1 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %> |
测试
11、配置Tomcat 启动测试!这里没有配置项目发布名,就是一个 / ,所以请求不用加项目名。
注解版
创建项目
1、新建一个Moudle,springmvc-03-annotation 。添加web支持!(由于Maven可能存在资源过滤的问题,若有遇到资源无法导出可点这里查看解决方法。)
依赖
2、在pom.xml文件引入相关的依赖。(我们在父工程中已经导入需要的依赖)
web.xml
3、配置web.xml,同上。
SpringMVC配置文件
4、添加Spring MVC配置文件,注意与上边的区别。
在resources目录下添加springmvc-servlet.xml配置文件,配置的形式与Spring容器配置基本类似,为了支持基于注解的IOC,设置了自动扫描包的功能(将bean注册到Spring容器),具体配置信息如下:
1 |
|
context:component-scan
- 让IOC的注解生效(自动扫描包将bean注册到Spring容器)mvc:default-servlet-handler
- 静态资源过滤 :HTML . JS . CSS . 图片 , 视频 …(可省略)mvc:annotation-driven
- MVC的注解驱动(可省略)ViewResolver
- 配置视图解析器(可省略)- 在视图解析器中我们把所有的视图都存放在/WEB-INF/目录下,这样可以保证视图安全,因为这个目录下的文件,客户端不能直接访问。
Controller
5、创建Controller,注意与上边的区别。
编写一个Java控制类:com.kuang.controller.HelloController , 注意编码规范
1 |
package com.kuang.controller; |
- 点这里复习注解。
- ==@Controller==是为了让Spring IOC容器初始化时自动扫描到。(@Controller本质是一个@Component,通过该注解可将bean注册到Spring容器中)
- ==@RequestMapping==是为了映射请求路径,这里因为类与方法上都有映射所以访问时应该是/HelloController/hello;
- 方法中声明==Model类型==的参数是为了把Action中的数据带到视图中;
- 方法返回的结果是==视图的名称hello==,加上配置文件中的前后缀变成WEB-INF/jsp/hello.jsp。(SpringMVC实现页面转发)
- 如果不想使用视图解析器,只是想返回json类型的数据(返回字符串)。@Controller改为==@RestController==,去掉参数model即可。
页面
6、创建视图层,同上。
测试
7、配置Tomcat运行
配置Tomcat ,开启服务器,访问对应的请求路径!
小结
实现步骤其实非常的简单:
- 新建一个web项目
- 导入相关jar包
- 编写web.xml , 注册DispatcherServlet
- 编写springmvc配置文件
- 接下来就是去创建对应的控制类 , controller
- 最后完善前端视图和controller之间的对应
- 测试运行调试.
使用springMVC必须配置的三大件:
处理器映射器、处理器适配器、视图解析器
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的xml配置
再来回顾下原理吧~
问题
可能遇到的问题:访问出现404,排查步骤:
- 查看控制台输出,看一下是不是缺少了什么jar包。
- 如果jar包存在,显示无法输出(依赖jar包没有添加到打包后的项目文件中),就在IDEA的项目发布中,添加lib依赖!
- 点击工具栏的“File” –> Project Structure(项目结构) –> Artifacts(可理解为项目打包后的文件,对其进行设置)
- 选择我们的项目 –> 打开”<output root>”下的“WEB-INF”文件夹,若其中没有“lib“文件夹则新建一个并点击”+“号将“Library Files“中的所有jar包添加进去
- 重启Tomcat 即可解决!
小结:看这个估计大部分同学都能理解其中的原理了,但是我们实际开发才不会这么写,不然就疯了,还学这个玩意干嘛!我们来看个注解版实现,这才是SpringMVC的精髓。
RestFul风格
概念
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
功能
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
分别对应 添加、 删除、修改、查询。
传统方式操作资源 :通过==不同的参数==来实现不同的效果!方法单一,post 和 get
1 |
http://127.0.0.1/item/queryItem.action?id=1 查询,GET |
使用RESTful操作资源 :可以通过==不同的请求方式==来实现不同的效果!如下:请求地址一样,但是功能可以不同!
1 |
http://127.0.0.1/item/1 查询,GET |
使用method属性指定请求类型
用于约束请求的类型,可以收窄请求范围。指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等。
测试
在新建一个类 RestFulController
1
2
3
public class RestFulController {
}两种风格对比
在Spring MVC中可以使用==@PathVariable==注解,让方法参数绑定URI上的路径。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class RestFulController {
//RestFul风格
"/commit/{p1}/{p2}") (
public String test(@PathVariable int p1, @PathVariable int p2, Model model){
int result = p1+p2;
//Spring MVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", p1+"+"+p2+"="+result);
//返回视图位置
return "hello";
}
//传统方式
"/commit") (
public String test0(int p1, int p2, Model model){
int result = p1+p2;
//Spring MVC会自动实例化一个Model对象用于向视图中传值
model.addAttribute("msg", p1+"+"+p2+"="+result);
//返回视图位置
return "hello";
}
//扩展:一样的请求路径,不同的请求方式(get、post、put...),实现不同效果(对应不同方法)
"/hello",method = RequestMethod.GET)//GetMapping (path =
public String test1(){
return "hello";
}
"/hello") (path =
public String test2(){
return "hello";
}
"/hello") (path =
public String test3(){
return "hello";
}
"/hello") (path =
public String test4(){
return "hello";
}
}测试
RestFul风格的请求方式,要传递的参数值直接作为请求路径的一部分
传统方式(get请求),要将参数拼接在请求路径后边
思考:使用路径变量的好处?
使路径变得更加简洁。
获得参数更加方便,框架会自动进行类型转换。
通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法,如这里访问是的路径是/commit/1/“1”,则路径与方法不匹配,而不会是参数转换失败。
小结
Spring MVC的@RequestMapping注解能够处理 HTTP 请求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH。
所有的地址栏请求默认都会是 HTTP GET 类型的。
方法级别的注解变体有如下几个:组合注解
1 |
@GetMapping |
@GetMapping 是一个组合注解,平时使用的会比较多!
它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一个快捷方式。
扩展:小黄鸭调试法
场景一:我们都有过向别人(甚至可能向完全不会编程的人)提问及解释编程问题的经历,但是很多时候就在我们解释的过程中自己却想到了问题的解决方案,然后对方却一脸茫然。
场景二:你的同行跑来问你一个问题,但是当他自己把问题说完,或说到一半的时候就想出答案走了,留下一脸茫然的你。
其实上面两种场景现象就是所谓的小黄鸭调试法(Rubber Duck Debuging),又称橡皮鸭调试法,它是我们软件工程中最常使用调试方法之一。
此概念据说来自《程序员修炼之道》书中的一个故事,传说程序大师随身携带一只小黄鸭,在调试代码的时候会在桌上放上这只小黄鸭,然后详细地向鸭子解释每行代码,然后很快就将问题定位修复了。
数据处理及跳转
结果跳转方式
ModelAndView
设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面。
页面 : {视图解析器前缀} + viewName +{视图解析器后缀}
1 |
<!-- 视图解析器 --> |
对应的controller类。(前边的SpringMVC“配置版”例子中就是使用ModelAndView)
1 |
public class ControllerTest1 implements Controller { |
ServletAPI
通过设置ServletAPI , 不需要视图解析器。
1、通过HttpServletResponse进行输出
2、通过HttpServletResponse实现重定向
3、通过HttpServletResponse实现转发
1 |
|
SpringMVC
通过SpringMVC来实现转发和重定向 - 无需视图解析器;
测试前,需要将视图解析器注释掉
1 |
|
通过SpringMVC来实现转发和重定向 - 有视图解析器;
重定向 , 不需要视图解析器 , 本质就是重新请求一个新地方嘛 , 所以注意路径问题。
可以重定向到另外一个请求实现。(前边的SpringMVC“注解版”例子中就是使用SpringMVC实现转发)
1 |
|
数据处理
处理提交数据
1、提交的参数名称和处理方法的形参名称一致
提交数据 : http://localhost:8080/hello?name=kuangshen
处理方法 :
1 |
"/hello") ( |
后台输出 : kuangshen
2、提交的参数名称和处理方法的形参名称不一致
提交数据 : http://localhost:8080/hello?username=kuangshen
处理方法 :
1 |
//@RequestParam("username") : username提交的域的名称 . |
后台输出 : kuangshen
3、提交的是一个对象
要求提交的各个参数名和对象的属性名一致 , 形参使用对象即可
1、实体类
1 |
public class User { |
2、提交数据 : http://localhost:8080/mvc04/user?name=kuangshen&id=1&age=15
3、处理方法 :
1 |
"/user") ( |
后台输出 : User { id=1, name=’kuangshen’, age=15 }
说明:如果使用对象的话,前端传递的参数名和对象属性名必须一致,否则就是null。
数据显示到前端
第一种 : 通过ModelAndView
我们前面一直都是如此。就不过多解释
1 |
public class ControllerTest1 implements Controller { |
第二种 : 通过ModelMap
ModelMap
1 |
"/hello") ( |
第三种 : 通过Model
Model(前边的SpringMVC“注解版”例子中就是使用Model)
1 |
"/ct2/hello") ( |
对比
对于新手而言使用区别就是:
1 |
Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解; |
当然以后开发考虑的更多的是性能和优化,就不能单单仅限于此的了解。
请使用80%的时间打好扎实的基础,剩下18%的时间研究框架,2%的时间去学点英文,框架的官方文档永远是最好的教程。
乱码问题
测试步骤:
1、我们可以在首页编写一个提交的表单
1 |
<form action="/e/t" method="post"> |
2、后台编写对应的处理类
1 |
|
3、输入中文测试,发现乱码
不得不说,乱码问题是在我们开发中十分常见的问题,也是让我们程序猿比较头大的问题!
解决方法
以前遇到乱码问题可以自己写过滤器解决 , 但是==SpringMVC给我们提供了一个过滤器== , 我们可以直接使用,在web.xml中进行如下配置:
1 |
<!--配置SpringMVC的乱码过滤--> |
拓展
如果还是出现乱码的情况,可以进行如下配置。
方法1:修改tomcat配置文件 :设置编码!(conf文件夹下的server.xml文件)
1 |
<!--找到Connector标签,添加URIEncoding="utf-8"--> |
方法2:自定义过滤器(网上大神写的)。在web.xml中配置这个过滤器即可!
1 |
package com.kuang.filter; |
JSON交互处理
什么是JSON?
- JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛。
- 采用完全独立于编程语言的文本格式来存储和表示数据。
- 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
- 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
在 JavaScript 语言中,一切都是对象。因此,任何JavaScript 支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。看看他的要求和语法格式:
- ==对象==表示为==键值对==,数据由==逗号分隔==
- ==花括号==保存==对象==
- ==方括号==保存==数组==
JSON 键值对是用来保存 JavaScript 对象的一种方式,和 JavaScript 对象的写法也大同小异,键/值对组合中的==键==名写在前面并用==双引号 “” 包裹==,使用==冒号 : 分隔==,然后紧接着值:
1 |
{"name": "QinJiang"} |
很多人搞不清楚 JSON 和 JavaScript 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:
JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,==本质是一个字符串==。
1 |
var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的 |
JSON字符串和JS对象互转
要实现从JSON字符串==转换为==JavaScript ==对象==,使用 JSON.==parse()==方法:
1 |
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); |
要实现从JavaScript 对象==转换为==JSON==字符串==,使用 JSON.==stringify()== 方法:
1 |
var json = JSON.stringify({a: 'Hello', b: 'World'}); |
代码测试
1、新建一个module ,springmvc-05-json , 添加web的支持
2、在web目录下新建一个 json-1.html , 编写测试内容
1 |
<!DOCTYPE html> |
3、在IDEA中使用浏览器打开,查看控制台输出!
返回JSON
Jackson应该是目前比较好的json解析工具了。当然工具不止这一个,比如还有阿里巴巴的 fastjson 等等。
Jackson
我们这里使用Jackson,使用它需要导入它的jar包;
1 |
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> |
web.xml的配置:
1 |
|
SpringMVC配置:
1 |
|
我们随便编写一个User的实体类,然后我们去编写我们的测试Controller;
1 |
package com.kuang.pojo; |
这里我们需要两个新东西,一个是@ResponseBody,一个是ObjectMapper对象,我们看下具体的用法。
- ==@ResponseBody==的作用其实是将java对象转为json格式的数据并返回
- @responseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据。
- 注意:在使用此注解之后不会再走视图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。
- @ResponseBody是作用在方法上的,@ResponseBody 表示该方法的返回结果直接写入 HTTP response body 中,一般在异步获取数据时使用【也就是AJAX】。
- 更多介绍,点这里。
- ==Object Mapper==,Jackson对象映射器,可以把JSON解析为用户自定义类对象, 或者解析为JSON内置的树模型的对象(可以实现Java对象与JSON字符串的相互转换)
- ObjectMapper可以从字符串、流或文件解析JSON,并创建Java对象或对象图来表示已解析的JSON。将JSON解析为Java对象也称为从JSON反序列化Java对象。
- ObjectMapper也可以从Java对象创建JSON。 从Java对象生成JSON的过程也被称为序列化Java对象到JSON。
- 更多介绍,点这里。
编写一个Controller;
1 |
|
配置Tomcat , 启动测试一下!
发现出现了乱码问题,我们需要设置一下他的编码格式为utf-8,以及它返回的类型。(返回的json数据出现乱码,前边配置的过滤器也没有无法解决)
通过@RequestMaping的produces属性来实现,修改代码如下:(可以在SpringMVC配置文件中进行统一配置)
1 |
//produces:指定响应体返回类型和编码 |
再次测试, http://localhost:8080/json1 , 乱码问题OK!
【注意:使用json记得处理乱码问题】
拓展
前边jackson演示了将普通java对象转化为json字符串返回到前端,下边演示返回其他类型的数据。
返回集合
增加一个新的方法
1 |
"/json2") ( |
运行结果 : 十分完美,没有任何问题!(ArrayList集合被转化为一个数组)
返回时间对象
增加一个新的方法
1 |
"/json3") ( |
运行结果 :
- 默认日期格式会变成一个数字,是1970年1月1日到当前日期的毫秒数!
- Jackson默认是会把时间转成timestamps形式(时间戳)
解决方案:取消timestamps形式 , 自定义时间格式
1 |
"/json4") ( |
运行结果 : 成功的输出了时间!
抽取为工具类
如果要经常使用的话,这样是比较麻烦的,我们可以将这些代码封装到一个工具类中
1 |
package com.kuang.utils; |
我们使用工具类,代码就更加简洁了!
1 |
"/json5") ( |
Fastjson
更多详细介绍,见Fastjson 简明教程。
fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。实现json的转换方法很多,最后的实现结果都是一样的。
fastjson的pom依赖!
1 |
<dependency> |
2022-5,fastjson被曝出存在“反序列化漏洞”。受影响范围小于等于1.2.80,修复版本为1.2.83或者使用2.x版本。
三个主要的类
JSONObject
JSONObject代表json对
- JSONObject实现了Map接口, 猜想 JSONObject底层操作是由Map实现的。
- JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size(),isEmpty()等方法获取”键:值”对的个数和判断是否为空。其本质是通过实现Map接口并调用接口中的方法完成的。
JSONArray
JSONArray代表json对象数组
- 内部是有List接口中的方法来完成操作的。
JSON
JSON代表JSONObject和JSONArray的转化
- JSON类源码分析与使用
- 仔细观察这些方法,主要是实现json对象,json对象数组,javabean对象,json字符串之间的相互转化。
代码测试,我们新建一个FastJsonDemo类:
1 |
package com.kuang.controller; |
这种工具类,我们只需要掌握使用就好了,在使用的时候在根据具体的业务去找对应的实现。和以前的commons-io那种工具包一样,拿来用就好了!
解析JSON
Gson
Google Gson是一个简单的基于Java的库,用于将Java对象序列化为JSON,也可以把JSON转换为Java对象。与上边的Jackson、Fastjson相似。更多详细介绍,见Github。
pom依赖:
1 |
<dependency> |
案例
JSON对象转换(解析)为Java对象。
对象转换
java实体类:
1 |
package com.jxstar.store; |
转换:
1 |
String repo = req.getRequestValue("repo");//获取json字符串 |
数组转换
java实体类:
1 |
package com.jxstar.store; |
转换和应用:
1 |
String dataList = req.getRequestValue("dataList");//获取json字符串 |
问题
乱码优化
在@RequestMapping中配置比较麻烦,如果项目中有许多请求则每一个都要添加,可以通过Spring配置统一指定,这样就不用每次都去处理了!
我们可以在springmvc的配置文件上添加一段消息StringHttpMessageConverter转换配置!
1 |
<!--开启SpringMVC注解驱动--> |
@ResponseBody优化
在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody!我们在前后端分离开发中,一般都使用@RestController ,十分便捷!
1 |
|
启动tomcat测试,结果都正常输出!
整合SSM
环境要求
环境:
- IDEA
- MySQL 5.7.19
- Tomcat 9
- Maven 3.6
要求:
- 需要熟练掌握MySQL数据库,Spring,JavaWeb及MyBatis知识,简单的前端知识;
数据库环境
创建一个存放书籍数据的数据库表
1 |
CREATE DATABASE `ssmbuild`; |
基本环境搭建
1、新建Maven项目!ssmbuild , 添加web的支持
2、导入相关的pom依赖!
1 |
<dependencies> |
3、Maven资源过滤设置
1 |
<build> |
4、建立基本结构和配置框架!
com.kuang.pojo
com.kuang.dao
com.kuang.service
com.kuang.controller
mybatis-config.xml(MyBatis配置文件)
1
2
3
4
5
6
7
<configuration>
</configuration>- database.properties(数据库配置文件)
applicationContext.xml(Spring配置文件 – 主)
1
2
3
4
5
6
7
<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>- spring-dao.xml(Spring整合MyBatis)
- spring-service.xml(Spring整合service层)
spring-mvc.xml(SpringMVC配置文件)
Mybatis层编写
1、数据库配置文件 database.properties
1 |
com.mysql.jdbc.Driver = |
2、IDEA关联数据库(非必须)
3、编写MyBatis的核心配置文件,mybatis-config.xml
1 |
|
4、编写数据库对应的实体类 com.kuang.pojo.Books
使用lombok插件!
1 |
package com.kuang.pojo; |
5、编写Dao层的 Mapper接口!
1 |
package com.kuang.dao; |
6、编写接口对应的 Mapper.xml 文件(前边进行了资源导出配置,这里mapper配置文件放在与接口相同的包下即可)。需要导入MyBatis的包;(不想写mapper配置文件可以使用注解,一般复杂查询注解就无能为力了还是得使用mapper配置文件)
1 |
|
编写好mapper配置文件后,要到MyBatis配置文件中注册(注册映射器)。我们使用包扫描自动注册的方式,这样就不需要每个mapper配置文件都手动注册。
1 |
<!-- 包扫描,自动注册映射器(接口和mapper配置文件要同名--> |
7、编写Service层的接口和实现类
接口:
1 |
package com.kuang.service; |
实现类:
1 |
package com.kuang.service; |
OK,到此,底层需求操作编写完毕!
Spring层
1、配置Spring整合MyBatis,我们这里数据源使用c3p0连接池;
2、我们去编写Spring整合Mybatis(dao)的相关的配置文件:==spring-dao.xml==
- 可以将数据库配置直接写在下边的dataSource中,也可以通过关联数据库文件的形式进行配置,下边的配置就是在Spring的配置文件中通过关联数据库文件database.properties配置datasource。
- 这里的dataSource使用c3p0而不是Spring提供的。
- 可以手动将DAO接口注册到Spring中,也可以跟下边一样通过扫描Dao接口包动态注册到spring容器中
1 |
|
3、Spring整合service层
我们去编写Spring整合service层的相关的配置文件:==spring-service.xml==。如果出现红色提示,是因为各个配置文件还没整合在一起,可以提前看看后边的整合设置,将xml文件整合在一起。(事务管理器的使用可以参考这里,下边还没有配置完全。注意:前边的service模块中并未使用到注解,所以下边的方式一并未起作用。)
1 |
|
Spring层搞定!再次理解一下,Spring就是一个大杂烩,一个容器!对吧!
SpringMVC层
1、添加web的支持!(选中module,点击鼠标右键,选择“Add Framework Support…”,再选择“Web Application”,确认即可)
2、web.xml
1 |
|
3、SpringMVC的配置文件:spring-mvc.xml
1 |
|
4、Spring配置整合文件,applicationContext.xml
1 |
|
SSM框架整合基本环境搭建备份:https://cloud.189.cn/t/bEFjA3YnEv2u(访问码:sfw9)
Controller和视图层
配置文件,暂时结束!Controller和视图层编写
1、BookController 类编写 , 方法一:查询全部书籍(使用fastjson进行json数据转换)
1 |
|
2、编写首页 index.jsp(web文件夹下,与WEB-INF文件夹同级)
1 |
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> |
效果:
3、书籍列表页面 allbook.jsp(WEB-INF文件夹下,新建jsp文件夹存放该jsp页面)。(使用Element-UI组件库来搭建页面,使用Vue进行数据绑定。也使用了jsp。)
1 |
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> |
效果:
4、BookController 类中继续编写 , 方法二:添加书籍
1 |
"/toAddBook")//实际路径为“/book/toAddBook",别忘记了类上配置的路径。 ( |
5、添加书籍页面:addBook.jsp
- vue-axios,get方式提交数据给服务器
1 |
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> |
效果:
6、BookController 类编写 , 方法三:修改书籍
1 |
"/toUpdateBook") ( |
7、修改书籍页面 updateBook.jsp
1 |
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> |
8、BookController 类编写 , 方法四:删除书籍
1 |
"/del/{bookId}") ( |
配置Tomcat,进行运行!
到目前为止,这个SSM项目整合已经完全的OK了,可以直接运行进行测试!这个练习十分的重要,大家需要保证,不看任何东西,自己也可以完整的实现出来!
项目结构图
注解
Controller
- @Controller - 会进行视图解析
- @RestController - 返回字符串
- @RequestMapping - 配置请求路径
- @RequestMapping的变体:
- @GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping、…
RestFul
- @PathVariable - URL中的路径与参数进行映射
接收参数:
- @RequestParam - 设置参数名
返回数据:
@ResponseBody - 将java对象转为json格式的数据并返回(不会走视图解析器)
@RestController - 对@ResponseBody的使用优化
小技巧
解决乱码
Json工具类,使用到json解析工具Jackson