写在前面:
SpringMVC是前端和后端交互的连接点.所以不可避免的需要一些前端的知识,因此我们会插入一些简单的前端知识.可以酌情阅读.
大概步骤:
SpringMVC的使用,然后通过注解再使用,然后重新学习一下重定向和转发.
解决一下其他问题,比如乱码过滤.统一数据传递(JSON).
前端的一些小知识:Ajax使用,优化一下我们的页面.
整合一下我们的SSM,然后用到我们之前学过的,让我们的页面更能看.
1.SpringMVC入门
我们首先要导入maven依赖,可以通过网上的maven仓库进行搜索并添加.
<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>
以后的所有maven都不再介绍了.这些依赖的作用从名字或者之前我们已经介绍过了.这里不再细讲了.
本章不涉及源码部分讲解,毕竟谁入门怼源码啊,源码是进阶所要了解的.
1.1 什么是MVC
MVC这个我们之前在学javaWeb的时候已经有了一些了解了.下面我们重新介绍以下MVC.
MVC就是一个设计模式.就是强制性的将应用程序的输入,处理和输出分开.
M:model
(模型):用于完成业务逻辑,由javaBean
构成.可以被多个视图重复使用
V:view
(视图):与用户交互的界面,由jsp,html
构成.不进行业务的处理,仅仅作为一个展示的界面和数据的传输.
C:Controller
(控制器):接受请求,调用模型,根据结构跳转到不同的视图.
这样可以使我们的分工更加明确,降低耦合,能够 提高代码的复用 和 降低维护难度.
这一点相信各位经过mybatis
和spring
的学习已经有了一部分体会了.能够有这样的优点是多么的舒服.
1.2 回顾servlet
既然和前端有关系,我们就少不了和javaWeb打交道,所以先来回顾一下servlet
.
写一个简单的servlet
控制的web
项目.
-
首先我们要写一个
servlet
来继承HttpServlet
.重写doGet
和doPost
方法.跳转到另一个网页package com.admin.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 { //取得参数 //业务逻辑 //视图跳转 req.getRequestDispatcher("WEB-INF/jsp/hello.jsp").forward(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
-
在
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.admin.servlet.helloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>helloServlet</servlet-name> <url-pattern>/helloServlet</url-pattern> </servlet-mapping> </web-app>
-
写一下对应的
jsp
页面<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>Hello</h1> </body> </html>
-
在tomcat中启动.,输入http://localhost:8080/helloServlet可以看到跳转到了hello页面.
那么我们的springMVC既然要实现这些功能,那么就至少包含了:
- 将url映射到java类或java类的方法中.
- 封装用户的提交数据.
- 处理请求–调用相关的业务处理–封装相应数据.
- 将相应的数据进行渲染.jsp/html等表示层数据.
1.3 SpringMVC简介
首先贴出自学标配-官方文档:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#spring-web
这个文档感觉比spring
文档少一点…
首先!SpringMVC用的人非常多
- SpringMVC是Spring Framework的一部分,基于Java实现MVC的轻量级Web框架.(简单易学,是Spring的一部分)
- 是一个基于请求响应的MVC框架.
- 功能强大:
RESTful
,数据验证,格式化,本地化,主题.
SpringMVC是一个围绕DispatcherServlet
(调度Servlet)涉及的web框架.
官网上在1.1.1 ContestHiderarchy
中直接简单介绍了DispatcherServlet
.感觉不是很容易理解.
我们先跟着写一个例子再来根据例子分析一下SpringMVC的执行原理.
先有鱼,再有渔.
1.4 一个简单的SpringMVC样例
官方整个1. SpringWebMVC就是介绍的SpringMVC.没有一个快速入门的案例.我们不用官方的步骤.自己先搞一个.
-
首先有一个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"> </beans>
-
然后在
web.xml
中注册DispatcherServlet
.这里我们用的servlet
是spring
的,以后我们的操作只需要在springmvc-servlet.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"> <!--1.注册DispatcherServlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--关联一个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>
-
在
spring-servlet.xml
中配置一些固定配置.<!--添加 处理映射器--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!--添加 处理器适配器--> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!--视图解析器:DispatcherServlet给他的ModelAndView--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean>
-
编写一个
controller
类实现Controller
接口.重写ModelAndView
方法
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//模型和视图
ModelAndView mv = new ModelAndView();
//封装对象,放入ModeAndView中
mv.addObject("msg","HelloSpringMVC");
//封装要跳转的视图
mv.setViewName("hello");
return mv;
}
}
将这个我们的这个类放入容器中
<!--将我们的Controller配置进来-->
<bean id="/hello" class="com.admin.controller.MyController"/>
-
将
hello.jsp
补充完整<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${msg} </body> </html>
-
配置
tomcat
,输入http://localhost:8080/hello
.来查看是否正常运行.
注意点:如果网站404,但是自己代码没有问题的话,查看输出(out
)中是否包含所需要的全部jar包
如果完成上面的步骤,相信大家已经有了一个大概的想法,下面我们就具体的分析一下.
1.5 SpringMVC再介绍.
通过上面的例子,我们来补全一下SpringMVC的实现流程
SpringMVC由前端控制器(DispatcherServlet
)来整体控制.我们通过在web.xml
注册DispatcherServlet
来获得.
获得DispatcherServlet
之后,我们需要绑定配置文件,就是我们的springmvc-servlet.xml
配置文件了.
这样,我们的核心DispatcherServlet
就配置好了.
准备好DispatcherServlet
后,我们就能通过该前端控制器来实现接受请求和响应资源了.
下面就来详细说一下从用户发出请求到收到响应和页面的过程.
- 接受请求:用户通过url向服务器发送请求.
DispatcherServlet
接受请求. - 查找目标:
DispatcherServlet
为了知道要跳转的目标,就向HandlerMapping
(处理器映射器)查找.HandlerMapping
根据url找出Handler
(处理器) - 返回目标:
HandlerExecution
将找到的Handler
并解析,然后将解析出来的信息返回给DispatcherServlet
. - 调用目标:
DispatcherServlet
为了能够找到正确的目标,调用HandlerAdapter
(处理器适配器)进行适配.然后按照特定的规则执行Handler
. - 执行目标:
Handler
让具体的Controller
执行.这里就是我们实现了Controller
接口的类. - 返回执行信息:
Controller
执行完后,将执行完的信息返回给HandlerAdapter
.例子中返回了ModelAndView
. - 返回处理信息:
HandlerAdapter
将返回的执行信息处理一遍,比如获得视图逻辑名或者模型传递给DispatcherServlet
,以便让前端控制器知道应该返回什么样的视图. - 查找视图:
DispatcherServlet
调用ViewResolver
(视图解析器)来解析HandlerAdapter
传来的逻辑视图名,以便知道我们要调用的视图. - 返回查找到的视图:
ViewResolver
将解析后的逻辑视图名传给DispatcherServlet
. - 调用视图:
DispatcherServlet
通过传过来的视图结果来调用具体的视图. - 用户看到视图.
DispatcherServlet
调用后,用户就能收到对应的视图,然后看到了.
关系可能有点多,等我画个图,然后删减一下就好了.
看,这个整体来说也就三个部分.通过DispatcherServlet
来进行管理.由此可见DispatcherServlet
的重要性.
其中,很多步骤我们都不需要写,回顾我们的入门样例.我们只写了:
Controller
:这就是我们要处理的业务,这部分需要我们自己完成.HandlerAdapter
:需要进行配置,是有规范的.View
:需要进行我们的视图实现.
至于中间的跳转部分,SpringMVC已经帮我们做好了.这样不仅减少了不同模块之间的耦合度,还方便了程序的开发.
再来观察我们的样例:
- 注册
DispatcherServlet
.然后创建一个springmvc-servlet.xml
文件与之绑定.这个xml文件就是我们的springmvc配置文件. - 在
springmvc-servlet.xml
中添加处理映射器HandlerMapping
和处理器适配器HandlerAdapter
.然后配置视图解析器ViewResolver
. - 写下我们的
HelloController
类来实现Controller
接口,用来处理业务和返回ModelAndView
. - 在我们的
springmvc-servlet.xml
中将我们的Controller
放入容器中.我们的HandlerMapping
就是通过找这个bean
来找到我们的目标Controller
的. - 在jsp包下创建我们的返回视图
hello.jsp
. - 配置tomcat然后运行.
按照这个步骤再来重写一便我们的样例,应该能有更深刻的理解了.
这里就不重写了.
到了这里,这些配置显得并不比多配一个servlet更加简单,这是因为我们是为了了解一下原理.下面使用注解来进行开发,让我们的代码更加简便.
2. SpringMVC的注解使用
使用注解开发就是省略的很多无意义且有规律的代码,比如
- 将类注入到ioc中.
- 添加处理映射器和处理器适配器等支持.
- 视图解析器的反应等.
2.1 一个简单的入门案例
老规矩,还是先来一个简单的入门案例,然后通过案例来分析.
我们来看一下流程:
-
注册
DispatcherServlet
并创建一个spring-servlet.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"> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-servlet.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
-
配置
springmvc-servlet.xml
文件然后添加注解支持,扫描包,添加springmvc的处理器映射器和处理器适配器等支持.添加固定的视图解析器的支持.<?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.admin.controller"/> <!-- 让Spring MVC不处理静态资源 比如html,css等资源 --> <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>
-
在我们的
com.admin.controller
下写我们的业务代码package com.admin.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller//表明是一个Controller public class HelloController { @RequestMapping("/hello")//配置对应的mapper.能被映射器找到. public String hello(Model model){ model.addAttribute("msg","HelloSpringMVC");//Model是为了将数据带入视图中 return "hello";//返回一个String,表示视图的名字,要被视图解析器解析. } }
-
在创建对应的目录
/WEB-INF/jsp/
下的hello.jsp
文件.<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${msg} </body> </html>
-
配置tomcat,我们来测试一下:
是不是简单多了,我们以后扩充业务,只需要在com.admin.contoller
包下,添加一个有一个的类和在对应的WEB-INF/jsp/
下添加对应的jsp就好了.减少了很多重复的规律代码.
2.2 注解的介绍
下面针对上面用到的两个注解来进行介绍.不过大概用法应该都能猜出来了.
2.2.1 @Controller和@RestController
@Controller
标注该类为一个controller.走视图解析器
回忆一下我们的IOC容器的注解:Spring入门中的4.2属性的注入@Component.
下面为原文内容:
@Component:将一个类装配到spring容器中,效果等同配置中的:
<bean id = "..." class = "..." />
在MVC三层架构中,不同层使用的注解有不同的标识,作用都是一样的(将某个类装配到spring容器中)目的只是为了区分不同的层。
- @Respository:用在dao层的注解
- @Service:用在Service层的注解
- @Controller:用在controller层的注解
这里用到的就是controller这个注解,就是用在了这里.由此可见我们的伏笔已经早已埋下了
- 使用这个注解表示这个类会被Spring接管.
- 被这个注解的类中的所有方法,如果返回值是Spring类型,并且有具体的页面跳转,就会被视图解析器解析.
- 如果想返回一个String类型的对象,不走视图解析器的话,使用
@RestController
.
知道这些使用就行了,有兴趣的自行翻看源码.
@RestController.
这个类下面的所有方法都不走视图解析器.
2.2.2 @RequestMapping
其实根据名字和我们一开始的xml样例可以推测出来大概的用法了.下面来做一下总结
- 用于映射url到控制器类或一个特定的处理程序的方法.可用于类或方法上.
- 类上:就是作为父路径,下面的子路径都需要先经过父路径才行.
- 用到方法上直接就是一个地址了.
- 推荐只用在方法上,多的话可以方便排错.
- 可以和
RestFul风格
搭配使用.
2.2.3 @RequestBody和@RequestParam.
@RequestBody和@RequestParam
都可以接受参数.通过注解在接受的参数前面可以实现参数的接受.
@RequsetBody
- 通过
body
来传递参数.由于通过请求体接收数据,因此前端要使用post来提交数据. - 一个方法中同时只能使用一个
@RequsetBody
来接受参数.
@RequestParam
- 用作接受前端传来的指定参数,用过该注解之后,必须传参,哪怕是null都行,但不能不传.
2.2.4 @ResponseBody
在方法上加上@ResponseBody
后,该方法就不会走视图解析器,会直接返回一个字符串.
@Controller
public class JsonController {
@RequestMapping("/json")
@ResponseBody
public String json1(){
User user = new User("cm",22,"hn","666");
return user.toString();
}
}
可以看出我们访问了json后返回了一个字符串.
2.2.4 RestFul风格介绍
概念:
Restful就是一个资源定位及资源操作的风格.不是标准也不是协议.只是一种风格.基于这个风格涉及的软件可以更简洁,更有层次,更易于实现缓存等机制.
功能:
- 资源:互联网的所有事物都可以被抽象为资源.
- 资源操作:包括
POST
,GET
,DELETE
,PUT
,使用不同的方法对资源进行操作. - 分别对应添加,查询,删除,修改.
对比:
**传统的方式操作资源:**通过不同的参数来实现不同的效果,get
和post
.参数可见.
http://localhost:8080/item/query.action?id=1//查找操作
http://localhost:8080/item/delete.action?id=2//删除操作.
**RestFul风格操作资源:**通过不同的请求方式来实现不同的效果.
http://localhost:8080/item //通过post请求,增加
http://localhost:8080/item/1 //通过get请求,查询
http://localhost:8080/item //通过put请求,修改.
代码对比
传统方法进行使用传参:
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(int a,int b,Model model){
model.addAttribute("msg",a+b);
return "hello";
}
}
样例输出:
可以看到,我们通过?来进行传参.
RestFul风格进行传参:
样例一:
@Controller
public class HelloController {
@RequestMapping("/hello/{a}/{b}")
public String hello(@PathVariable int a,@PathVariable int b, Model model){
model.addAttribute("msg",a+b);
return "hello";
}
}
样例输出:
可以看到我们的传参方式得到了改变.
样例二:
@Controller
public class HelloController {
@RequestMapping(value = "/hello/{a}/{b}",method = RequestMethod.GET)
public String hello(@PathVariable int a,@PathVariable int b, Model model){
model.addAttribute("msg",a+b);
return "hello";
}
@RequestMapping(path = "/hello/{a}/{b}",method = RequestMethod.POST)//这里value和path是一样的.
public String hello2(@PathVariable int a,@PathVariable int b, Model model){
model.addAttribute("msg",""+a+""+b);
return "hello";
}
}
写一个表单来改变我们的提交方法(写死我们的提交url)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="/hello/1/2" method="post">
<input type="submit">
</form>
</body>
</html>
我们直接在url中输入http://loaclhost:8080/hello/1/2
然后回车后:浏览器默认用的get方法.
然后我们通过点击按钮来提交:
发现时刻以通过同一个url来实现不同的方法调用.
3. 转发和重定向
转发和重定向是web中用的非常广的方法.我们来介绍一下在SpringMVC中如何做到.
3.1 直接使用ServletAPI.
直接使用ServletAPI,不需要视图解析器,通过servlet来实现转发和重定向.
正如我们之前学的HttpServletRespones
和HttpServletRequest
一样
@Controller
public class HelloController {
@RequestMapping("/test1")
public void test1(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.sendRedirect("/test2.jsp");
}
@RequestMapping("/test2")
public void test2(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
request.getRequestDispatcher("/test2.jsp").forward(request,response);
}
}
3.2 SpringMVC方式-无视图解析器
通过SpringMVC来实现转发和重定向,无需视图解析器
注释掉视图解析器
@RequestMapping("/res/t1")
public String test1(){
return "/index.jsp";
}
@RequestMapping("/res/t2")
public String test2(){
return "forward:/index.jsp";//转发
}
@RequestMapping("/res/t3")
public String test3(){
return "redirect:/index.jsp";//重定向
}
3.3 SpringMVC方式-有视图解析器
用视图解析器之后默认就是转发.我们可以通过redirect
来使其重定向
@RequestMapping("/res/t4")
public String test4(){
return "index";
}
@RequestMapping("/res/t5")
public String test5(){
return "redirect:/index.jsp";
}
4. 接受请求参数及数据回显
4.1 接受请求参数
接受请求参数目前有三种方法.
4.1.1 参数名和接受名一样.
localhost:8080/t1?name=xxx
@RequestMapping("/t1")
public String test2(String name,Model model){
//接受前端请求参数
//返回结果
model.addAttribute("msg",name);
//视图跳转
return "test";
}
直接映射上去了.其他参数会显示null
.
4.1.2 参数名和接受名不一样
localhost:8080/t2?username=xxx
@RequestMapping("/t2")
public String test2(@RequestParam("username") String name,Model model){
//接受前端请求参数
//返回结果
model.addAttribute("msg",name);
//视图跳转
return "test";
}
这样只能传输username
属性,其他的会报错.
4.1.3 接受一个实体类.
通过对象名一一映射.我们有一个User
对象,包含id,name,age
.
localhost:8080/t3?id=1&name=xxx&age=10
@RequestMapping("/t3")
public String test2(User user,Model model){
//接受前端请求参数
System.out.println(user);
//返回结果
//视图跳转
return "test";
}
必须一一对应.否则会显示null
.
4.2 Model,ModelMap和ModeAndView
- Model:只有少量的方法,只是可用于存储数据,简化了新手对Model对象的操作和理解.
- ModeMap:继承了
LinkedMap
,除了实现了自身的一些方法,同样的继承Linked Map
的方法和特性. - ModelAndView:可以在存除视图的同时,可以进行设置返回的逻辑视图,进行控制展示曾的跳转.
5. SpringMVC的乱码过滤器
直接在web.xml
中添加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>
6. JSON
6.1 什么是JSON
可以看一下JSON
官网:https://www.json.org/json-en.html
JSON
,全称(JavaScript Object Notation
,JS
对象标记).是一个轻量级的数据交换格式,目前使用最为广泛.
- 采用完全独立于编程语言的文本格式来存除和表示数据.
- 类似
XML
,存储和交换文本信息的语法,但JSON
比XML
更小,更快,更易解析.
6.2 JSON小样例.
我们先通过一个小样例来熟悉一下JSON
.
创建一个web
文本(HTML,JSP
都可以).这里我用的jsp
.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JavaScript中通过JSON创建对象</title>
</head>
<body>
<div>
name: <span id="jName"></span><br/>
age: <span id="jAge"></span><br/>
address: <span id="jAddress"></span><br/>
phone: <span id="jPhone"></span><br/>
</div>
<script type="text/javascript">
var JSONObject={
"name":"cm",
"age":"22",
"address":"hn",
"phone":"666"
};
document.getElementById("jName").innerText=JSONObject.name
document.getElementById("jAge").innerText=JSONObject.age
document.getElementById("jAddress").innerText=JSONObject.address
document.getElementById("jPhone").innerText=JSONObject.phone
</script>
</body>
</html>
可以看出效果:
解释一下:这里是定义了一个JSONObject
的JSON
变量,然后通过js使变量的值赋予到文本中.
6.3 JSON 再介绍.
6.3.1 JSON和XML的区分.
JSON
相对于XML
更加小巧易使用.下面做一下区分
- 与
XML
相同点:- 都是纯文本,具有自我描述性(人类可读).
- 具有层级结构(值中存在值).
- 可通过
JavaScript
传输,可以用Ajax
进行传输.
- 与
XML
相比的优势:- 学习成本更低.
- 读写速度更快,更短.
- 可以使用
JavaScript
直接解析. - 使用数组,没有保留字.没有结束标签.
知道优势之后,我们来看一下JSON
的语法结构.
6.3.2 JSON的语法结构.
JSON
构建于两种结构:
-
键值对.
var temp{ "key1":"1", "key2":"value" }
-
数组.
var temp[value1,"value2"] //可以通过temp[0].value1 = "value1.1";来进行修改和赋值.
补充:JSON
的文件类型为".json"
.JSON
文本的MIME
类型是"application/json"
.
6.3.3 JSON的使用
JSON
最常见的用法之一就是从web服务器上读取JSON
数据(作为文件或作为HttpRequest
).将JSON
数据转换为JavaScript
对象.然后在网页中使用该对象.
通过eval()
函数可以将一个字符串改变成JSON
对象.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>通过 JSON 字符串来创建对象</title>
</head>
<body>
<p>
First Name: <span id="fname"></span><br />
Last Name: <span id="lname"></span><br />
</p>
<script type="text/javascript">
var txt = '{"employees":[' +
'{"firstName":"Bill","lastName":"Gates" },' +
'{"firstName":"George","lastName":"Bush" },' +
'{"firstName":"Thomas","lastName":"Carter" }]}';
var obj = eval ("(" + txt + ")");
document.getElementById("fname").innerHTML=obj.employees[1].firstName
document.getElementById("lname").innerHTML=obj.employees[1].lastName
</script>
</body>
</html>
当然,这只是个示范,我们可以通过更有效和安全的方式来获取JSON
对象.直接通过JSON解析器
来获取JSON
对象.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>通过 JSON 字符串来创建对象</title>
</head>
<body>
<p id="demo"></p>
<script>
var txt = '{"name":"Bill Gates", "age":62, "city":"Seattle"}'
var obj = JSON.parse(txt);
document.getElementById("demo").innerHTML = obj.name + ", " + obj.age;
</script>
</body>
</html>
在前端JSON
可以通过两种方法来实现对象和字符串之间的转换
JSON.parse()
将字符串转换成一个JSON
对象.JSON.stringify()
将一个JSON
对象转换成字符串.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<script type="text/javascript">
var person = {
"name":"cm",
age:22,
"address":"hn",
"phone":"666"
};
var text = "{ \"name\":\"cm\"}";
var json = JSON.parse(text);
var string = JSON.stringify(person);
console.log("字符串:"+text+"变为对象:");
console.log(json)
console.log(person);
console.log("对象:"+person+"字符串"+string);
</script>
</body>
</html>
可以在浏览器的日志中看到:
6.4 JSON的处理
6.4.1 JSON的后端向前端传递.
介绍了那么多关于JSON
的使用和概念,我们该回到我们的出发点了.即:将后端的数据传输给前端.
Contriller
返回JSON
数据.
首先导入工具类(jar包)当然,这么简单我们自己写也行.这个包的作用就是给我们提供一些关于JSON
的方法.
<dependency>
<groupId>com.fasterxml.jaskson.core</groupId>
<artifactId>jaskson-databind</artifactId>
<version>2.10.0</version>
</dependency>
配置完web.xml
和springmvc-servlet.xml
就可以使用了.我们最常用的,将一个对象或者数据传递给前端.
首先存在一个pojo
类.
package com.admin.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private int age;
private String address;
private String phone;
}
编写对应的Controller来对它进行操作.
package com.admin.controller;
import com.admin.pojo.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
//@RestController
@Controller
public class JsonController {
@RequestMapping("/json1")
@ResponseBody//不走视图解析器,注解部分有介绍.
public String json1() throws JsonProcessingException {
User user = new User("cm",22,"hn","666");
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(user);
return str;
}
}
访问这个url,看一下返回结果:就是一个简单的字符串封装,我们自己也可以完成的.
然后在前端接受,然后处理一下就可以实现前端接受数据了.
如何处理,我们就可以试试用Ajax来处理.
6.5 JSON的其他使用问题
6.5.1 乱码问题1.
我们的值传递给客户端的时候如果里面有中文,可能出现中文乱码.在@RequsetMapping
中添加一个参数produces = "application/json;charset=utf-8"
就好了:
@Controller
public class JsonController {
@RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")
@ResponseBody
public String json1() throws JsonProcessingException {
User user = new User("cm",22,"我到河北省来","666");
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(user);
return str;
}
}
输出示范:
6.5.1 乱码问题2
如果要设置的produces = "application/json;charset=utf-8"
比较多,我们可以在springMVC
的xml
中统一配置乱码解决方案.
<!--解决JSON乱码问题-->
<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>
可以看出效果和方法一是一样的:
7. SSM整合
学习路线:mybatis
,spring
,springmvc
.一阶段一整合.
7.1 环境要求.
前提配置.
- IDEA
- MySql 5.5
- Tomcat 8.5.50
- Maven 3.5.2
首先存在一个存放书籍数据的数据库列表
create table books(
bookID int auto_increment comment '书id' ,
bookName varchar(100) comment '书名' ,
bookCounts int(11) comment '数量' ,
detail varchar(200) comment '描述' ,
key bookID (bookID)
)engine=innodb default charset=utf8;
insert into books (bookName,bookCounts,detail) values
('a',1,'第一本'),
('b',3,'第二本'),
('c',3,'第三本');
7.2 简单整合Mybatis和Spring
-
然后创建一个普通的
maven
项目,导入依赖包.- 数据库驱动
mysql-connector-java
,连接池c3p0
,mybatis
,mybatis-spring
spring-webmvc,spring-jdbc.
servlet,jsp,jstl
junit
- 数据库驱动
-
创建配置文件
-
mybatis:
mybatis-config.xml
其中一部分通过spring来做就可以了.<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <typeAliases> <package name="com.admin.pojo"/> </typeAliases> <mappers> <mapper resource="com/admin/dao/BooksMapper.xml"/> </mappers> </configuration>
-
spring:
-
spring-mybatis.xml
.配置我们的spring和mybatis整合<?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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!--配置数据源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 绑定mybatis配置文件 --> <property name="configLocation" value="classpath:mybatis-config.xml"/> <!-- 配置映射器mapper 当然也可以在mybatis-config中配置 --> <!--<property name="mapperLocations" value="classpath:com/admin/dao/UserMapper.xml"/>--> </bean> <!--SqlSessionTemplate 就是我们使用的sqlSession--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> </beans>
-
applicationContext.xml
导入我们的spring-mybatis.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <import resource="spring-mybatis.xml"/> </beans>
-
-
springmvc:
servletmvc-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>
-
-
创建对应的接口和类.
-
dao
:BooksMapper
,BooksMapperImpl
package com.admin.dao; import com.admin.pojo.Books; import org.apache.ibatis.annotations.Param; import java.util.List; public interface BooksMapper { /** * 增删改查 * @param books */ int addBook(Books books); int deleteBook(@Param("bookId") int id); int updataBook(Books books); Books selectBookById(@Param("bookId") int id); List<Books> selectAllBook(); }
package com.admin.dao.impl; import com.admin.dao.BooksMapper; import com.admin.pojo.Books; import org.apache.ibatis.session.SqlSession; import org.mybatis.spring.SqlSessionTemplate; import java.util.List; public class BookMapperImpl implements BooksMapper { private SqlSessionTemplate sqlSession; public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } public int addBook(Books books) { BooksMapper mapper = sqlSession.getMapper(BooksMapper.class); return mapper.addBook(books); } public int deleteBook(int id) { BooksMapper mapper = sqlSession.getMapper(BooksMapper.class); return mapper.deleteBook(id); } public int updataBook(Books books) { BooksMapper mapper = sqlSession.getMapper(BooksMapper.class); return mapper.updataBook(books); } public Books selectBookById(int id) { BooksMapper mapper = sqlSession.getMapper(BooksMapper.class); return mapper.selectBookById(id); } public List<Books> selectAllBook() { BooksMapper mapper = sqlSession.getMapper(BooksMapper.class); return mapper.selectAllBook(); } }
-
pojo
:Books
package com.admin.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Books { private int bookID; private String bookName; private int bookCounts; private String detail; }
-
service
:BooksService
,BooksServiceImpl
package com.admin.service; import com.admin.pojo.Books; import org.apache.ibatis.annotations.Param; import java.util.List; public interface BooksService { /** * 增删改查 * @param books */ int addBook(Books books); int deleteBook(int id); int updataBook(Books books); Books selectBookById(int id); List<Books> selectAllBook(); }
package com.admin.service.impl; import com.admin.dao.BooksMapper; import com.admin.pojo.Books; import com.admin.service.BooksService; import java.util.List; public class BooksServiceImpl implements BooksService { private BooksMapper booksMapper; public void setBooksMapper(BooksMapper booksMapper) { this.booksMapper = booksMapper; } public int addBook(Books books) { return booksMapper.addBook(books); } public int deleteBook(int id) { return booksMapper.deleteBook(id); } public int updataBook(Books books) { return booksMapper.updataBook(books); } public Books selectBookById(int id) { return booksMapper.selectBookById(id); } public List<Books> selectAllBook() { return booksMapper.selectAllBook(); } }
-
-
再
applicationContext.xml
中注册bean<bean id="booksMapper" class="com.admin.dao.impl.BookMapperImpl"> <property name="sqlSession" ref="sqlSession"/> </bean> <bean id="booksService" class="com.admin.service.impl.BooksServiceImpl"> <property name="booksMapper" ref="booksMapper"/> </bean>
-
编写一个测试类来尝试一下我们是否写错了.
public class MyTest { @Test public void addBook(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); BooksService booksService = context.getBean("booksService", BooksService.class); booksService.addBook(new Books(4,"d",4,"第四本")); } @Test public void selectAll(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); BooksService booksService = context.getBean("booksService", BooksService.class); List<Books> books = booksService.selectAllBook(); for (Books book : books) { System.out.println(book); } } } /*输出部分: Checking to see if class com.admin.pojo.Books matches criteria [is assignable to Object] Creating a new SqlSession SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@44be0077] was not registered for synchronization because synchronization is not active JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@66fdec9] will not be managed by Spring ==> Preparing: select * from books; ==> Parameters: <== Columns: bookID, bookName, bookCounts, detail <== Row: 1, a, 1, 第一个 <== Row: 2, b, 3, 第二个 <== Row: 3, c, 3, 第三个 <== Row: 4, d, 4, 第四本 <== Total: 4 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@44be0077] Books(bookID=1, bookName=a, bookCounts=1, detail=第一个) Books(bookID=2, bookName=b, bookCounts=3, detail=第二个) Books(bookID=3, bookName=c, bookCounts=3, detail=第三个) Books(bookID=4, bookName=d, bookCounts=4, detail=第四本) */
7.3 整合SpringMVC
-
添加web项目支持.
-
补全
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"> <!--1.注册DispatcherServlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--关联一个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> <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"> <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 --> <context:component-scan base-package="com.admin.controller"/> <!-- 让Spring MVC不处理静态资源 比如html,css等资源 --> <mvc:default-servlet-handler /> <!--支持mvc注解驱动--> <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.admin.controller; import com.admin.pojo.Books; import com.admin.service.BooksService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import java.util.List; @Controller public class HelloController { @RequestMapping("/hello") public String hello(Model model){ System.out.println("进入Hello"); ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); BooksService booksService = context.getBean("booksService", BooksService.class); List<Books> books = booksService.selectAllBook(); model.addAttribute("books",books); return "hello"; } }
-
补充跳转的
hello.jsp
.再WEB-INF/jsp/
目录下.<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>Hello</h1> ${books} </body> </html>
-
补全tomcat配置,注意输出的lib中是否存在所有的包.否则可能爆
404
. -
优化页面.
后面就是重复的东西了.写前端页面,后端也一样.
8.拦截器
8.1 拦截器概述
SpringMVC
的处理器拦截器类似于Servlet
开发中的过滤器Filter
,用于对处理器进行预处理和后处理,开发者可以自己定义一些拦截器来实现特定的功能.
过滤器和拦截器的区别:拦截器是AOP
思想的具体应用.
过滤器
Servlet
规范中的一部分,任何javaweb
工程都可以使用.- 在
url-pattern
中配置了/*
之后,就可以对所有要访问的资源进行拦截.
拦截器
- 拦截器是
SpringMVC
框架自己的,只有使用了SpringMVC
框架的工程才能使用. - 拦截器只会拦截访问的控制器方法,如果访问的是
jsp,html,css,image,js
等是不会进行拦截的.
8.2 拦截器简单样例.
定义一个拦截器需要实现HandlerInterceptor
接口.
package com.admin.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("=======拦截前========");
return true;
}
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("=======拦截后========");
}
}
设置controller
package com.admin.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class InterceptorController {
@RequestMapping("/t1")
public String t1(){
System.out.println("success");
return "success";
}
}
然后再applicationContext.xml
中配置拦截器.
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.admin.config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
重启tomcat
测试:
控制台输出:
=======拦截前========
success
=======拦截中========
=======拦截后========
页面输出:success
其实就这么点东西
9.小结
控制器Controller
.
- 负责提供应用程序的行为,通常通过实现接口或注解定义两种实现方式.
- 负责解析用户的请求并将其转换为一个模型(model).
- 在SpringMVC中一个控制器可以包含多个方法.
- 在SpringMVC中一个控制器可以有多种配置.
映射器RequestMapping
- 用于映射url到控制器类或一个特定的处理程序的方法.可用于类或方法上.
- 可以和
RestFul风格
搭配使用.