SpringMVC学习笔记
什么是MVC?
-
MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
-
是将业务逻辑、数据、显示分离的方法来组织代码。
-
MVC主要作用是降低了视图与业务逻辑间的双向偶合。
-
MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。
最典型的MVC就是JSP + servlet + javabean的模式。

MVC框架要做哪些事情?
将url映射到java类或java类的方法 .
封装用户提交的数据 .
处理请求–调用相关的业务处理–封装响应数据 .
将响应的数据进行渲染 . jsp / html 等表示层数据 .
Model1时代(这个时代的java代码直接写在jsp里面)

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 <dependencies> 2 <dependency> 3 <groupId>junit</groupId> 4 <artifactId>junit</artifactId> 5 <version>4.12</version> 6 </dependency> 7 <dependency> 8 <groupId>org.springframework</groupId> 9 <artifactId>spring-webmvc</artifactId> 10 <version>5.1.9.RELEASE</version> 11 </dependency> 12 <dependency> 13 <groupId>javax.servlet</groupId> 14 <artifactId>servlet-api</artifactId> 15 <version>2.5</version> 16 </dependency> 17 <dependency> 18 <groupId>javax.servlet.jsp</groupId> 19 <artifactId>jsp-api</artifactId> 20 <version>2.2</version> 21 </dependency> 22 <dependency> 23 <groupId>javax.servlet</groupId> 24 <artifactId>jstl</artifactId> 25 <version>1.2</version> 26 </dependency> 27 </dependencies>
-
建立一个Moudle:springmvc-01-servlet , 添加Web app的支持!
-
导入servlet 和 jsp 的 jar 依赖
1 <dependency> 2 <groupId>javax.servlet</groupId> 3 <artifactId>servlet-api</artifactId> 4 <version>2.5</version> 5 </dependency> 6 <dependency> 7 <groupId>javax.servlet.jsp</groupId> 8 <artifactId>jsp-api</artifactId> 9 <version>2.2</version> 10 </dependency>
编写一个Servlet类,用来处理用户的请求
1 package com.kuang.servlet; 2 3 //实现Servlet接口 4 public class HelloServlet extends HttpServlet { 5 @Override 6 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 7 //取得参数 8 String method = req.getParameter("method"); 9 if (method.equals("add")){ 10 req.getSession().setAttribute("msg","执行了add方法"); 11 } 12 if (method.equals("delete")){ 13 req.getSession().setAttribute("msg","执行了delete方法"); 14 } 15 //业务逻辑 16 //视图跳转 17 req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req,resp); 18 } 19 20 @Override 21 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 22 doGet(req,resp); 23 } 24 }
编写Hello.jsp,在WEB-INF目录下新建一个jsp的文件夹,新建hello.jsp
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <html> 3 <head> 4 <title>Kuangshen</title> 5 </head> 6 <body> 7 ${msg} 8 </body> 9 </html>
在web.xml中注册Servlet
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 5 version="4.0"> 6 <servlet> 7 <servlet-name>HelloServlet</servlet-name> 8 <servlet-class>com.kuang.servlet.HelloServlet</servlet-class> 9 </servlet> 10 <servlet-mapping> 11 <servlet-name>HelloServlet</servlet-name> 12 <url-pattern>/user</url-pattern> 13 </servlet-mapping> 14 15 </web-app>
配置Tomcat,并启动测试
-
localhost:8080/user?method=add
-
localhost:8080/user?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拆分成三部分:
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根据视图解析器解析的视图结果,调用具体的视图。
-
最终视图呈现给用户。

快速入门【这里是根据原理来进行配置的一个demo没有使用注解】
创建项目导入依赖
创建Maven的简单项目,在pom.xml中导入依赖
1 <!--导入依赖--> 2 <dependencies> 3 <!--测试--> 4 <dependency> 5 <groupId>junit</groupId> 6 <artifactId>junit</artifactId> 7 <version>4.13.2</version> 8 </dependency> 9 <!--mvc--> 10 <dependency> 11 <groupId>org.springframework</groupId> 12 <artifactId>spring-webmvc</artifactId> 13 <version>5.2.13.RELEASE</version> 14 </dependency> 15 <!--servlet--> 16 <dependency> 17 <groupId>javax.servlet</groupId> 18 <artifactId>servlet-api</artifactId> 19 <version>2.5</version> 20 </dependency> 21 <!--jsp--> 22 <dependency> 23 <groupId>javax.servlet.jsp</groupId> 24 <artifactId>jsp-api</artifactId> 25 <version>2.2</version> 26 </dependency> 27 <dependency> 28 <groupId>jstl</groupId> 29 <artifactId>jstl</artifactId> 30 <version>1.2</version> 31 </dependency> 32 </dependencies>
使Maven简单项目变成一个web项目


Web.xml中注册DispatcherServlet 在这个web.xml中关联 springmvc-servlet.xml 配置文件
1、所有请求走这里来 这里拦截所有请求
2、因为关联了springmvc-servlet.xml 配置文件,所以会去这个配置文件中找到url映射器和处理器映射器 handle
3、handle 适配器处理器就会去找具体的Controlller
4、因为在springmvc-servlet.xml 配置文件中,配置了Controller bean 并且配置了 /hello 所以会进入具体的Controller
5、进入controller会执行逻辑代码,访问业务层,dao层 返回数据(modelAndView)给DistpatherServlet
6、因为在springmvc-servlet.xml 配置文件中 配置了视图解析器 配置了前缀和后缀 所以对返回到页面视图的名称会进行截取
7、然后将数据返回到相应的jsp页面--->用户
1 <!--1.注册DispatcherServlet--> 2 <servlet> 3 <servlet-name>springmvc</servlet-name> 4 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 5 <!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml--> 6 <init-param> 7 <param-name>contextConfigLocation</param-name> 8 <param-value>classpath:springmvc-servlet.xml</param-value> 9 </init-param> 10 <!--启动级别-1--> 11 <load-on-startup>1</load-on-startup> 12 </servlet> 13 14 <!--/ 匹配所有的请求;(不包括.jsp)--> 15 <!--/* 匹配所有的请求;(包括.jsp)--> 16 <servlet-mapping> 17 <servlet-name>springmvc</servlet-name> 18 <url-pattern>/</url-pattern> 19 </servlet-mapping>
编写springmvc-servlet.xml配置文件 【这个配置文件中配置这url处理器映射,和适配器处理器handle】
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7 8 <!--处理器映射器--> 9 <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> 10 11 <!--处理器适配器--> 12 <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> 13 14 <!--视图解析器--> 15 <!--视图解析器:DispatcherServlet给他的ModelAndView--> 16 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> 17 <!--前缀--> 18 <property name="prefix" value="/WEB-INF/jsp/"/> 19 <!--后缀--> 20 <property name="suffix" value=".jsp"/> 21 </bean> 22 23 <!--handler--> 24 <bean id="/hello" class="com.tony.controller.HelloController"/> 25 </beans>
编写我们要操作业务Controller
要么实现Controller接口,要么增加注解;需要返回一个ModelAndView,装数据,封视图
1 /** 2 * 导入Controller接口 3 * @Author Tu_Yooo 4 * @create 2021/3/28 13:12 5 */ 6 public class HelloController implements Controller { 7 @Override 8 public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { 9 //ModelAndView 模型和视图 10 ModelAndView mv = new ModelAndView(); 11 //封装对象,放在ModelAndView中。Model 12 mv.addObject("msg","HelloSpringMVC!"); 13 //封装要跳转的视图,放在ModelAndView中 14 mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp 15 return mv; 16 } 17 }
在WEB-INF下创建hello.jsp文件

启动测试

访问出现404,排查步骤
1.查看jar依赖是否正确导入
2.如果jar包存在,显示无法输出,就在IDEA的项目发布中添加lib依赖!
3.重启Tomcat即可解决




快速入门-注解版
新建项目导入依赖
由于Maven可能存在资源过滤问题,将pom.xml完善
1 <build> 2 <resources> 3 <resource> 4 <directory>src/main/java</directory> 5 <includes> 6 <include>**/*.properties</include> 7 <include>**/*.xml</include> 8 </includes> 9 <filtering>false</filtering> 10 </resource> 11 <resource> 12 <directory>src/main/resources</directory> 13 <includes> 14 <include>**/*.properties</include> 15 <include>**/*.xml</include> 16 </includes> 17 <filtering>false</filtering> 18 </resource> 19 </resources> 20 </build>
3、在pom.xml文件引入相关的依赖:主要有Spring框架核心库、Spring MVC、servlet , JSTL等。我们在父依赖中已经引入了!
4、配置web.xml Web.xml中注册DispatcherServlet
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 5 version="4.0"> 6 7 <!--1.注册servlet--> 8 <servlet> 9 <servlet-name>SpringMVC</servlet-name> 10 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 11 <!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--> 12 <init-param> 13 <param-name>contextConfigLocation</param-name> 14 <param-value>classpath:springmvc-servlet.xml</param-value> 15 </init-param> 16 <!-- 启动顺序,数字越小,启动越早 --> 17 <load-on-startup>1</load-on-startup> 18 </servlet> 19 20 <!--所有请求都会被springmvc拦截 --> 21 <servlet-mapping> 22 <servlet-name>SpringMVC</servlet-name> 23 <url-pattern>/</url-pattern> 24 </servlet-mapping> 25 26 </web-app>
/ 和 /* 的区别:< url-pattern > / </ url-pattern > 不会匹配到.jsp, 只针对我们编写的请求;即:.jsp 不会进入spring的 DispatcherServlet类 。< url-pattern > /* </ url-pattern > 会匹配 *.jsp,会出现返回 jsp视图 时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。
-
注意web.xml版本问题,要最新版!
-
注册DispatcherServlet
-
关联SpringMVC的配置文件
-
启动级别为1
-
映射路径为 / 【不要用/*,会404】
5、添加Spring MVC配置文件
在resource目录下添加springmvc-servlet.xml配置文件,配置的形式与Spring容器配置基本类似,为了支持基于注解的IOC,设置了自动扫描包的功能,具体配置信息如下:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:mvc="http://www.springframework.org/schema/mvc" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/context 9 https://www.springframework.org/schema/context/spring-context.xsd 10 http://www.springframework.org/schema/mvc 11 https://www.springframework.org/schema/mvc/spring-mvc.xsd"> 12 13 <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 --> 14 <context:component-scan base-package="com.kuang.controller"/> 15 <!-- 让Spring MVC不处理静态资源 --> 16 <mvc:default-servlet-handler /> 17 <!-- 18 支持mvc注解驱动 19 在spring中一般采用@RequestMapping注解来完成映射关系 20 要想使@RequestMapping注解生效 21 必须向上下文中注册DefaultAnnotationHandlerMapping 22 和一个AnnotationMethodHandlerAdapter实例 23 这两个实例分别在类级别和方法级别处理。 24 而annotation-driven配置帮助我们自动完成上述两个实例的注入。 25 --> 26 <mvc:annotation-driven /> 27 28 <!-- 视图解析器 --> 29 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" 30 id="internalResourceViewResolver"> 31 <!-- 前缀 --> 32 <property name="prefix" value="/WEB-INF/jsp/" /> 33 <!-- 后缀 --> 34 <property name="suffix" value=".jsp" /> 35 </bean> 36 37 </beans>
在视图解析器中我们把所有的视图都存放在/WEB-INF/目录下,这样可以保证视图安全,因为这个目录下的文件,客户端不能直接访问。
-
让IOC的注解生效
-
静态资源过滤 :HTML . JS . CSS . 图片 , 视频 …
-
MVC的注解驱动
-
配置视图解析器
6、创建Controller
编写一个Java控制类:com.kuang.controller.HelloController , 注意编码规范
1 package com.kuang.controller; 2 3 import org.springframework.stereotype.Controller; 4 import org.springframework.ui.Model; 5 import org.springframework.web.bind.annotation.RequestMapping; 6 7 @Controller 8 @RequestMapping("/HelloController") 9 public class HelloController { 10 11 //真实访问地址 : 项目名/HelloController/hello 12 @RequestMapping("/hello") 13 public String sayHello(Model model){ 14 //向模型中添加属性msg与值,可以在JSP页面中取出并渲染 15 model.addAttribute("msg","hello,SpringMVC"); 16 //web-inf/jsp/hello.jsp 17 return "hello"; 18 } 19 }
-
@Controller是为了让Spring IOC容器初始化时自动扫描到;
-
@RequestMapping是为了映射请求路径,这里因为类与方法上都有映射所以访问时应该是/HelloController/hello;
-
方法中声明Model类型的参数是为了把Action中的数据带到视图中;
-
方法返回的结果是视图的名称hello,加上配置文件中的前后缀变成WEB-INF/jsp/hello.jsp。
7、创建视图层
在WEB-INF/ jsp目录中创建hello.jsp , 视图可以直接取出并展示从Controller带回的信息;
可以通过EL表示取出Model中存放的值,或者对象;
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <html> 3 <head> 4 <title>SpringMVC</title> 5 </head> 6 <body> 7 ${msg} 8 </body> 9 </html>
8、配置Tomcat运行
配置Tomcat , 开启服务器 , 访问 对应的请求路径!

小结
实现步骤其实非常的简单:
-
新建一个web项目
-
导入相关jar包
-
编写web.xml , 注册DispatcherServlet
-
编写springmvc配置文件
-
接下来就是去创建对应的控制类 , controller
-
最后完善前端视图和controller之间的对应
-
测试运行调试.
使用springMVC必须配置的三大件:
处理器映射器、处理器适配器、视图解析器
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的xml配置
再来回顾下原理吧~

SpringMVC参数详解
Controller详解
控制器复杂提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现。
控制器负责解析用户的请求并将其转换为一个模型。
在Spring MVC中一个控制器类可以包含多个方法
在Spring MVC中,对于Controller的配置方式有很多种
实现Controller接口
Controller是一个接口,在org.springframework.web.servlet.mvc包下,接口中只有一个方法;
1 //实现该接口的类获得控制器功能 2 public interface Controller { 3 //处理请求且返回一个模型与视图对象 4 ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception; 5 }
测试
-
新建一个Moudle,springmvc-04-controller 。将刚才的03 拷贝一份, 我们进行操作!
-
删掉HelloController
-
mvc的配置文件只留下 视图解析器!
-
编写一个Controller类,ControllerTest1
1 //定义控制器 2 //注意点:不要导错包,实现Controller接口,重写方法; 3 public class ControllerTest1 implements Controller { 4 5 public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { 6 //返回一个模型视图对象 7 ModelAndView mv = new ModelAndView(); 8 mv.addObject("msg","Test1Controller"); 9 mv.setViewName("test"); 10 return mv; 11 } 12 }
编写完毕后,去Spring配置文件中注册请求的bean;name对应请求路径,class对应处理请求的类
1 <bean name="/t1" class="com.kuang.controller.ControllerTest1"/>
编写前端test.jsp,注意在WEB-INF/jsp目录下编写,对应我们的视图解析器
1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <html> 3 <head> 4 <title>Kuangshen</title> 5 </head> 6 <body> 7 ${msg} 8 </body> 9 </html>
配置Tomcat运行测试,我这里没有项目发布名配置的就是一个 / ,所以请求不用加项目名,OK!

说明:
-
实现接口Controller定义控制器是较老的办法
-
缺点是:一个控制器中只有一个方法,如果要多个方法则需要定义多个Controller;定义的方式比较麻烦;
使用注解@Controller
-
@Controller注解类型用于声明Spring类的实例是一个控制器(在讲IOC时还提到了另外3个注解);
-
Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。
1 <!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --> 2 <context:component-scan base-package="com.kuang.controller"/>
增加一个ControllerTest2类,使用注解实现;
1 //@Controller注解的类会自动添加到Spring上下文中 2 @Controller 3 public class ControllerTest2{ 4 5 //映射访问路径 6 @RequestMapping("/t2") 7 public String index(Model model){ 8 //Spring MVC会自动实例化一个Model对象用于向视图中传值 9 model.addAttribute("msg", "ControllerTest2"); 10 //返回视图位置 11 return "test"; 12 } 13 14 }
可以发现,我们的两个请求都可以指向一个视图,但是页面结果的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱偶合关系。
注解方式是平时使用的最多的方式!
RequestMapping
@RequestMapping
-
@RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
-
为了测试结论更加准确,我们可以加上一个项目名测试 myweb
-
只注解在方法上面
1 @Controller 2 public class TestController { 3 @RequestMapping("/h1") 4 public String test(){ 5 return "test"; 6 } 7 }
-
访问路径:http://localhost:8080 / 项目名 / h1
-
同时注解类与方法
1 @Controller 2 @RequestMapping("/admin") 3 public class TestController { 4 @RequestMapping("/h1") 5 public String test(){ 6 return "test"; 7 } 8 }
访问路径:http://localhost:8080 / 项目名/ admin /h1 , 需要先指定类的路径再指定方法的路径;
RestFul 风格 (@PathVariable 注解 的使用)
概念
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
功能
资源:互联网所有的事物都可以被抽象为资源
资源操作:使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。
分别对应 添加、 删除、修改、查询。
传统方式操作资源 :通过不同的参数来实现不同的效果!方法单一,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
使用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
学习测试
在新建一个类 RestFulController
1 @Controller 2 public class RestFulController { 3 }
在Spring MVC中可以使用 @PathVariable 注解,让方法参数的值对应绑定到一个URI模板变量上。
1 @Controller 2 public class RestFulController { 3 4 //映射访问路径 5 @RequestMapping("/commit/{p1}/{p2}") 6 public String index(@PathVariable int p1, @PathVariable int p2, Model model){ 7 8 int result = p1+p2; 9 //Spring MVC会自动实例化一个Model对象用于向视图中传值 10 model.addAttribute("msg", "结果:"+result); 11 //返回视图位置 12 return "test"; 13 14 } 15 16 }
我们来测试请求查看下

-
思考:使用路径变量的好处?
-
使路径变得更加简洁;
-
获得参数更加方便,框架会自动进行类型转换。 (如果参数类型不匹配的话,那么进行请求就会报错)
-
通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法,如这里访问是的路径是/commit/1/a,则路径与方法不匹配,而不会是参数转换失败。

我们来修改下对应的参数类型,再次测试
1 //映射访问路径 2 @RequestMapping("/commit/{p1}/{p2}") 3 public String index(@PathVariable int p1, @PathVariable String p2, Model model){ 4 5 String result = p1+p2; 6 //Spring MVC会自动实例化一个Model对象用于向视图中传值 7 model.addAttribute("msg", "结果:"+result); 8 //返回视图位置 9 return "test"; 10 11 }

使用method属性指定请求类型
用于约束请求的类型,可以收窄请求范围。指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等
我们来测试一下:
-
增加一个方法
1 //映射访问路径,必须是POST请求 2 @RequestMapping(value = "/hello",method = {RequestMethod.POST}) 3 public String index2(Model model){ 4 model.addAttribute("msg", "hello!"); 5 return "test"; 6 }
我们使用浏览器地址栏进行访问默认是Get请求,会报错405:

如果将POST修改为GET则正常了;
1 //映射访问路径,必须是Get请求 2 @RequestMapping(value = "/hello",method = {RequestMethod.GET}) 3 public String index2(Model model){ 4 model.addAttribute("msg", "hello!"); 5 return "test"; 6 }

Spring MVC 的 @RequestMapping 注解能够处理 HTTP 请求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH。
所有的地址栏请求默认都会是 HTTP GET 类型的。
方法级别的注解变体有如下几个:组合注解
1 @GetMapping 2 @PostMapping 3 @PutMapping 4 @DeleteMapping 5 @PatchMapping
@GetMapping 是一个组合注解,平时使用的会比较多!
它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一个快捷方式。
SpringMVC参数接收处理和结果跳转处理!
结果跳转方式
结果跳转方式有三种:
1.ModelAndView
2.原生的ServletAPI
3.SpringMVC的方式
一、ModelAndView
设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面 .
页面 : {视图解析器前缀} + viewName +{视图解析器后缀}
在xml中配置视图解析器
1 <!-- 视图解析器 --> 2 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" 3 id="internalResourceViewResolver"> 4 <!-- 前缀 --> 5 <property name="prefix" value="/WEB-INF/jsp/" /> 6 <!-- 后缀 --> 7 <property name="suffix" value=".jsp" /> 8 </bean>
对应的controller类 该Controller 不使用注解 而是实现 Controller 接口
1 public class ControllerTest1 implements Controller { 2 3 public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { 4 //返回一个模型视图对象 5 ModelAndView mv = new ModelAndView(); 6 mv.addObject("msg","ControllerTest1"); 7 mv.setViewName("test"); 8 return mv; 9 } 10 }
二、ServletAPI (这种方式比较古老) 即使用的是 原生的 Servlet 中 的request reponse对象进行数据的接收和视图的跳转
通过设置ServletAPI , 不需要视图解析器 .
1、通过HttpServletResponse进行输出
2、通过HttpServletResponse实现重定向
3、通过HttpServletResponse实现转发
1 @Controller 2 public class ResultGo { 3 4 @RequestMapping("/result/t1") 5 public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException { 6 rsp.getWriter().println("Hello,Spring BY servlet API"); 7 } 8 9 @RequestMapping("/result/t2") 10 public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException { 11 rsp.sendRedirect("/index.jsp"); 12 } 13 14 @RequestMapping("/result/t3") 15 public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception { 16 //转发 17 req.setAttribute("msg","/result/t3"); 18 req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp); 19 } 20 21 }
SpringMVC
通过SpringMVC来实现转发和重定向 - 也不需要视图解析器;
测试前,需要将视图解析器注释掉
1 @Controller 2 public class ResultSpringMVC { 3 @RequestMapping("/rsm/t1") 4 public String test1(){ 5 //转发 6 return "/index.jsp"; 7 } 8 9 @RequestMapping("/rsm/t2") 10 public String test2(){ 11 //转发二 12 return "forward:/index.jsp"; 13 } 14 15 @RequestMapping("/rsm/t3") 16 public String test3(){ 17 //重定向 18 return "redirect:/index.jsp"; 19 } 20 }
通过SpringMVC来实现转发和重定向 - 有视图解析器;
重定向 , 不需要视图解析器 , 本质就是重新请求一个新地方嘛 , 所以注意路径问题.
可以重定向到另外一个请求实现 .
1 @Controller 2 public class ResultSpringMVC2 { 3 @RequestMapping("/rsm2/t1") 4 public String test1(){ 5 //转发 6 return "test"; 7 } 8 9 @RequestMapping("/rsm2/t2") 10 public String test2(){ 11 //重定向 12 return "redirect:/index.jsp"; 13 //return "redirect:hello.do"; //hello.do为另一个请求/ 14 } 15 16 }
数据处理
处理提交数据
1、提交的域名称和处理方法的参数名一致
提交数据 : http://localhost:8080/hello?name=kuangshen
处理方法 :
1 @RequestMapping("/hello") 2 public String hello(String name){ 3 System.out.println(name); 4 return "hello"; 5 }
后台输出 : kuangshen
2、提交的域名称和处理方法的参数名不一致(则需要使用@RequestParam("xxx")注解) 中的 xxx 和前台的参数的key一致 然后后台实际和这个不一样 使用这个注解就可以匹配上了 示例:
提交数据 : http://localhost:8080/hello?username=kuangshen
处理方法 :
1 //@RequestParam("username") : username提交的域的名称 name 是后台接收的名称. 2 @RequestMapping("/hello") 3 public String hello(@RequestParam("username") String name){ 4 System.out.println(name); 5 return "hello"; 6 }
后台输出 : kuangshen
3、提交的是一个对象
要求提交的表单域和对象的属性名一致 , 参数使用对象即可
1、实体类
1 public class User { 2 private int id; 3 private String name; 4 private int age; 5 //构造 6 //get/set 7 //tostring() 8 }
2、提交数据 : http://localhost:8080/mvc04/user?name=kuangshen&id=1&age=15
3、处理方法 :
1 @RequestMapping("/user") 2 public String user(User user){ 3 System.out.println(user); 4 return "hello"; 5 }
后台输出 : User { id=1, name='kuangshen', age=15 }
说明:如果使用对象的话,前端传递的参数名和对象名必须一致,否则这个字段值就是null。
数据显示到前端
第一种 : 通过ModelAndView
我们前面一直都是如此 . 就不过多解释
1 public class ControllerTest1 implements Controller { 2 3 public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { 4 //返回一个模型视图对象 5 ModelAndView mv = new ModelAndView(); 6 mv.addObject("msg","ControllerTest1"); 7 mv.setViewName("test"); 8 return mv; 9 } 10 }
第二种 : 通过ModelMap
ModelMap
1 @RequestMapping("/hello") 2 public String hello(@RequestParam("username") String name, ModelMap model){ 3 //封装要显示到视图中的数据 4 //相当于req.setAttribute("name",name); 5 model.addAttribute("name",name); 6 System.out.println(name); 7 return "hello"; 8 }
第三种 : 通过Model
Model
1 @RequestMapping("/ct2/hello") 2 public String hello(@RequestParam("username") String name, Model model){ 3 //封装要显示到视图中的数据 4 //相当于req.setAttribute("name",name); 5 model.addAttribute("msg",name); 6 System.out.println(name); 7 return "test"; 8 }
对比
就对于新手而言简单来说使用区别就是:
Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;
ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;
ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
乱码问题
测试步骤:
1、我们可以在首页编写一个提交的表单
1 <form action="/e/t" method="post"> 2 <input type="text" name="name"> 3 <input type="submit"> 4 </form>
2、后台编写对应的处理类
1 @Controller 2 public class Encoding { 3 @RequestMapping("/e/t") 4 public String test(Model model,String name){ 5 model.addAttribute("msg",name); //获取表单提交的值 6 return "test"; //跳转到test页面显示输入的值 7 } 8 }
3、输入中文测试,发现乱码

不得不说,乱码问题是在我们开发中十分常见的问题,也是让我们程序猿比较头大的问题!
以前乱码问题通过过滤器解决 , 而SpringMVC给我们提供了一个过滤器 , 可以在web.xml中配置 .
修改了xml文件需要重启服务器!
注意这个/* 的问题 我们不能使用 /
/*可以出来请求和jsp页面
但是 / 只会处理请求 不会处理jsp
1 <filter> 2 <filter-name>encoding</filter-name> 3 <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 4 <init-param> 5 <param-name>encoding</param-name> 6 <param-value>utf-8</param-value> 7 </init-param> 8 </filter> 9 <filter-mapping> 10 <filter-name>encoding</filter-name> 11 <url-pattern>/*</url-pattern> 12 </filter-mapping>
但是我们发现 , 有些极端情况下.这个过滤器对get的支持不好 .
处理方法 :
1、修改tomcat配置文件 :设置编码!
1 <Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1" 2 connectionTimeout="20000" 3 redirectPort="8443" />
r如果还没有解决 则自定义过滤器进行处理:.
2、自定义过滤器 【需要在web.xml中配置这个过滤器】
1 package com.kuang.filter; 2 3 import javax.servlet.*; 4 import javax.servlet.http.HttpServletRequest; 5 import javax.servlet.http.HttpServletRequestWrapper; 6 import javax.servlet.http.HttpServletResponse; 7 import java.io.IOException; 8 import java.io.UnsupportedEncodingException; 9 import java.util.Map; 10 11 /** 12 * 解决get和post请求 全部乱码的过滤器 13 */ 14 public class GenericEncodingFilter implements Filter { 15 16 @Override 17 public void destroy() { 18 } 19 20 @Override 21 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 22 //处理response的字符编码 23 HttpServletResponse myResponse=(HttpServletResponse) response; 24 myResponse.setContentType("text/html;charset=UTF-8"); 25 26 // 转型为与协议相关对象 27 HttpServletRequest httpServletRequest = (HttpServletRequest) request; 28 // 对request包装增强 29 HttpServletRequest myrequest = new MyRequest(httpServletRequest); 30 chain.doFilter(myrequest, response); 31 } 32 33 @Override 34 public void init(FilterConfig filterConfig) throws ServletException { 35 } 36 37 } 38 39 //自定义request对象,HttpServletRequest的包装类 40 class MyRequest extends HttpServletRequestWrapper { 41 42 private HttpServletRequest request; 43 //是否编码的标记 44 private boolean hasEncode; 45 //定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰 46 public MyRequest(HttpServletRequest request) { 47 super(request);// super必须写 48 this.request = request; 49 } 50 51 // 对需要增强方法 进行覆盖 52 @Override 53 public Map getParameterMap() { 54 // 先获得请求方式 55 String method = request.getMethod(); 56 if (method.equalsIgnoreCase("post")) { 57 // post请求 58 try { 59 // 处理post乱码 60 request.setCharacterEncoding("utf-8"); 61 return request.getParameterMap(); 62 } catch (UnsupportedEncodingException e) { 63 e.printStackTrace(); 64 } 65 } else if (method.equalsIgnoreCase("get")) { 66 // get请求 67 Map<String, String[]> parameterMap = request.getParameterMap(); 68 if (!hasEncode) { // 确保get手动编码逻辑只运行一次 69 for (String parameterName : parameterMap.keySet()) { 70 String[] values = parameterMap.get(parameterName); 71 if (values != null) { 72 for (int i = 0; i < values.length; i++) { 73 try { 74 // 处理get乱码 75 values[i] = new String(values[i] 76 .getBytes("ISO-8859-1"), "utf-8"); 77 } catch (UnsupportedEncodingException e) { 78 e.printStackTrace(); 79 } 80 } 81 } 82 } 83 hasEncode = true; 84 } 85 return parameterMap; 86 } 87 return super.getParameterMap(); 88 } 89 90 //取一个值 91 @Override 92 public String getParameter(String name) { 93 Map<String, String[]> parameterMap = getParameterMap(); 94 String[] values = parameterMap.get(name); 95 if (values == null) { 96 return null; 97 } 98 return values[0]; // 取回参数的第一个值 99 } 100 101 //取所有值 102 @Override 103 public String[] getParameterValues(String name) { 104 Map<String, String[]> parameterMap = getParameterMap(); 105 String[] values = parameterMap.get(name); 106 return values; 107 } 108 }
在web.xm中配置
1 <!--配置自定义乱码过滤器--> 2 <filter> 3 <filter-name>encoding</filter-name> 4 <filter-class>com.tony.controller.EncodingFiler</filter-class> 5 </filter> 6 <filter-mapping> 7 <filter-name>encoding</filter-name> 8 <url-pattern>/*</url-pattern> 9 </filter-mapping>
Json交互处理:
什么是JSON?
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛。
JSON 键值对是用来保存 JavaScript 对象的一种方式,和 JavaScript 对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 "" 包裹,使用冒号 : 分隔,然后紧接着值:
很多人搞不清楚 JSON 和 JavaScript 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:
JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
1 var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的 2 var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串
JSON 和 JavaScript 对象互转
要实现从JSON字符串转换为JavaScript 对象,使用 JSON.parse() 方法:
1 var obj = JSON.parse('{"a": "Hello", "b": "World"}'); 2 //结果是 {a: 'Hello', b: 'World'}
要实现从JavaScript 对象转换为JSON字符串,使用 JSON.stringify() 方法:
1 var json = JSON.stringify({a: 'Hello', b: 'World'}); 2 //结果是 '{"a": "Hello", "b": "World"}'
Controller返回JSON数据:
Jackson应该是目前比较好的json解析工具了
当然工具不止这一个,比如还有阿里巴巴的 fastjson 等等。
我们这里使用Jackson,使用它需要导入它的jar包;
1 <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> 2 <dependency> 3 <groupId>com.fasterxml.jackson.core</groupId> 4 <artifactId>jackson-databind</artifactId> 5 <version>2.9.8</version> 6 </dependency>
配置SpringMVC需要的配置
web.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 5 version="4.0"> 6 7 <!--1.注册servlet--> 8 <servlet> 9 <servlet-name>SpringMVC</servlet-name> 10 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 11 <!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--> 12 <init-param> 13 <param-name>contextConfigLocation</param-name> 14 <param-value>classpath:springmvc-servlet.xml</param-value> 15 </init-param> 16 <!-- 启动顺序,数字越小,启动越早 --> 17 <load-on-startup>1</load-on-startup> 18 </servlet> 19 20 <!--所有请求都会被springmvc拦截 --> 21 <servlet-mapping> 22 <servlet-name>SpringMVC</servlet-name> 23 <url-pattern>/</url-pattern> 24 </servlet-mapping> 25 26 <filter> 27 <filter-name>encoding</filter-name> 28 <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 29 <init-param> 30 <param-name>encoding</param-name> 31 <param-value>utf-8</param-value> 32 </init-param> 33 </filter> 34 <filter-mapping> 35 <filter-name>encoding</filter-name> 36 <url-pattern>/</url-pattern> 37 </filter-mapping> 38 39 </web-app>
springmvc-servlet.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:mvc="http://www.springframework.org/schema/mvc" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/context 9 https://www.springframework.org/schema/context/spring-context.xsd 10 http://www.springframework.org/schema/mvc 11 https://www.springframework.org/schema/mvc/spring-mvc.xsd"> 12 13 <!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --> 14 <context:component-scan base-package="com.kuang.controller"/> 15 16 <!-- 视图解析器 --> 17 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" 18 id="internalResourceViewResolver"> 19 <!-- 前缀 --> 20 <property name="prefix" value="/WEB-INF/jsp/" /> 21 <!-- 后缀 --> 22 <property name="suffix" value=".jsp" /> 23 </bean> 24 25 </beans>
我们随便编写一个User的实体类,然后我们去编写我们的测试Controller:
1 package com.kuang.pojo; 2 3 import lombok.AllArgsConstructor; 4 import lombok.Data; 5 import lombok.NoArgsConstructor; 6 7 //需要导入lombok 8 @Data 9 @AllArgsConstructor 10 @NoArgsConstructor 11 public class User { 12 13 private String name; 14 private int age; 15 private String sex; 16 17 }
这里我们需要两个新东西,一个是@ResponseBody,一个是ObjectMapper对象,我们看下具体的用法
编写一个Controller; (这个是使用原生的jackson包将java对象转成 json格式的 控制层上使用 @ResponseBody会使得控制层直接返回字符串, 还可以使用 @RestController 注解 这个
注解是 @Controller 和 @ResponseBody 的结合体)
1 @Controller 2 public class UserController { 3 4 @RequestMapping("/json1") 5 @ResponseBody 6 public String json1() throws JsonProcessingException { 7 //创建一个jackson的对象映射器,用来解析数据 8 ObjectMapper mapper = new ObjectMapper(); 9 //创建一个对象 10 User user = new User("秦疆1号", 3, "男"); 11 //将我们的对象解析成为json格式 12 String str = mapper.writeValueAsString(user); 13 //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便 14 return str; 15 } 16 17 }
发现出现了乱码问题,我们需要设置一下他的编码格式为utf-8,以及它返回的类型;
通过@RequestMaping的produces属性来实现,修改下代码
1 //produces:指定响应体返回类型和编码 2 @RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")
再次测试, http://localhost:8080/json1 , 乱码问题OK!
【注意:使用json记得处理乱码问题】
乱码统一解决
上一种方法比较麻烦,如果项目中有许多请求则每一个都要添加,可以通过Spring配置统一指定,这样就不用每次都去处理了!
我们可以在springmvc的配置文件上添加一段消息StringHttpMessageConverter转换配置!
1 <mvc:annotation-driven> 2 <mvc:message-converters register-defaults="true"> 3 <bean class="org.springframework.http.converter.StringHttpMessageConverter"> 4 <constructor-arg value="UTF-8"/> 5 </bean> 6 <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> 7 <property name="objectMapper"> 8 <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> 9 <property name="failOnEmptyBeans" value="false"/> 10 </bean> 11 </property> 12 </bean> 13 </mvc:message-converters> 14 </mvc:annotation-driven>
返回json字符串统一解决
在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody !我们在前后端分离开发中,一般都使用 @RestController ,十分便捷!
1 @RestController 2 public class UserController { 3 4 //produces:指定响应体返回类型和编码 5 @RequestMapping(value = "/json1") 6 public String json1() throws JsonProcessingException { 7 //创建一个jackson的对象映射器,用来解析数据 8 ObjectMapper mapper = new ObjectMapper(); 9 //创建一个对象 10 User user = new User("秦疆1号", 3, "男"); 11 //将我们的对象解析成为json格式 12 String str = mapper.writeValueAsString(user); 13 //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便 14 return str; 15 } 16 17 }
测试集合输出:
增加一个新的方法
1 @RequestMapping("/json2") 2 public String json2() throws JsonProcessingException { 3 4 //创建一个jackson的对象映射器,用来解析数据 5 ObjectMapper mapper = new ObjectMapper(); 6 //创建一个对象 7 User user1 = new User("秦疆1号", 3, "男"); 8 User user2 = new User("秦疆2号", 3, "男"); 9 User user3 = new User("秦疆3号", 3, "男"); 10 User user4 = new User("秦疆4号", 3, "男"); 11 List<User> list = new ArrayList<User>(); 12 list.add(user1); 13 list.add(user2); 14 list.add(user3); 15 list.add(user4); 16 17 //将我们的对象解析成为json格式 18 String str = mapper.writeValueAsString(list); 19 return str; 20 }
输出时间对象
@RequestMapping("/json3")
public String json3() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//创建时间一个对象,java.util.Date
Date date = new Date();
//将我们的对象解析成为json格式
String str = mapper.writeValueAsString(date);
return str;
}
-
默认日期格式会变成一个数字,是1970年1月1日到当前日期的毫秒数!
-
Jackson 默认是会把时间转成timestamps形式
- 解决方案:取消timestamps形式 , 自定义时间格式(在这个 json工具包中可以设置处理时间格式)
@RequestMapping("/json4")
public String json4() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//不使用时间戳的方式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定义日期格式对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//指定日期格式
mapper.setDateFormat(sdf);
Date date = new Date();
String str = mapper.writeValueAsString(date);
return str;
}
抽取为工具类
如果要经常使用的话,这样是比较麻烦的,我们可以将这些代码封装到一个工具类中;我们去编写下(工具类)
1 package com.kuang.utils; 2 3 import com.fasterxml.jackson.core.JsonProcessingException; 4 import com.fasterxml.jackson.databind.ObjectMapper; 5 import com.fasterxml.jackson.databind.SerializationFeature; 6 7 import java.text.SimpleDateFormat; 8 9 public class JsonUtils { 10 11 public static String getJson(Object object) { 12 return getJson(object,"yyyy-MM-dd HH:mm:ss"); 13 } 14 15 public static String getJson(Object object,String dateFormat) { 16 ObjectMapper mapper = new ObjectMapper(); 17 //不使用时间差的方式 18 mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); 19 //自定义日期格式对象 20 SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); 21 //指定日期格式 22 mapper.setDateFormat(sdf); 23 try { 24 return mapper.writeValueAsString(object); 25 } catch (JsonProcessingException e) { 26 e.printStackTrace(); 27 } 28 return null; 29 } 30 }
我们使用工具类,代码就更加简洁了!
1 @RequestMapping("/json5") 2 public String json5() throws JsonProcessingException { 3 Date date = new Date(); 4 String json = JsonUtils.getJson(date); 5 return json; 6 }
fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。实现json的转换方法很多,最后的实现结果都是一样的。
fastjson 的 pom依赖!
1 <dependency> 2 <groupId>com.alibaba</groupId> 3 <artifactId>fastjson</artifactId> 4 <version>1.2.60</version> 5 </dependency>
fastjson 三个主要的类:
JSONObject 代表 json 对象
-
JSONObject实现了Map接口, 猜想 JSONObject底层操作是由Map实现的。
-
JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size(),isEmpty()等方法获取"键:值"对的个数和判断是否为空。其本质是通过实现Map接口并调用接口中的方法完成的。
JSONArray 代表 json 对象数组
-
内部是有List接口中的方法来完成操作的。
JSON代表 JSONObject和JSONArray的转化
-
JSON类源码分析与使用
-
仔细观察这些方法,主要是实现json对象,json对象数组,javabean对象,json字符串之间的相互转化。
代码测试,我们新建一个FastJsonDemo 类
1 package com.kuang.controller; 2 3 import com.alibaba.fastjson.JSON; 4 import com.alibaba.fastjson.JSONObject; 5 import com.kuang.pojo.User; 6 7 import java.util.ArrayList; 8 import java.util.List; 9 10 public class FastJsonDemo { 11 public static void main(String[] args) { 12 //创建一个对象 13 User user1 = new User("秦疆1号", 3, "男"); 14 User user2 = new User("秦疆2号", 3, "男"); 15 User user3 = new User("秦疆3号", 3, "男"); 16 User user4 = new User("秦疆4号", 3, "男"); 17 List<User> list = new ArrayList<User>(); 18 list.add(user1); 19 list.add(user2); 20 list.add(user3); 21 list.add(user4); 22 23 System.out.println("*******Java对象 转 JSON字符串*******"); 24 String str1 = JSON.toJSONString(list); 25 System.out.println("JSON.toJSONString(list)==>"+str1); 26 String str2 = JSON.toJSONString(user1); 27 System.out.println("JSON.toJSONString(user1)==>"+str2); 28 29 System.out.println("\n****** JSON字符串 转 Java对象*******"); 30 User jp_user1=JSON.parseObject(str2,User.class); 31 System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1); 32 33 System.out.println("\n****** Java对象 转 JSON对象 ******"); 34 JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2); 35 System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.getString("name")); 36 37 System.out.println("\n****** JSON对象 转 Java对象 ******"); 38 User to_java_user = JSON.toJavaObject(jsonObject1, User.class); 39 System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user); 40 } 41 }
这种工具类,我们只需要掌握使用就好了,在使用的时候在根据具体的业务去找对应的实现。和以前的commons-io那种工具包一样,拿来用就好了!
Controller返回JSON数据
整合SSM:
创建一个存放书籍数据的数据库表
1 CREATE DATABASE `ssmbuild`; 2 3 USE `ssmbuild`; 4 5 DROP TABLE IF EXISTS `books`; 6 7 CREATE TABLE `books` ( 8 `bookID` INT(10) NOT NULL AUTO_INCREMENT COMMENT '书id', 9 `bookName` VARCHAR(100) NOT NULL COMMENT '书名', 10 `bookCounts` INT(11) NOT NULL COMMENT '数量', 11 `detail` VARCHAR(200) NOT NULL COMMENT '描述', 12 KEY `bookID` (`bookID`) 13 ) ENGINE=INNODB DEFAULT CHARSET=utf8 14 15 INSERT INTO `books`(`bookID`,`bookName`,`bookCounts`,`detail`)VALUES 16 (1,'Java',1,'从入门到放弃'), 17 (2,'MySQL',10,'从删库到跑路'), 18 (3,'Linux',5,'从进门到进牢');
1、新建一Maven项目!ssmbuild , 添加web的支持
2、导入相关的pom依赖!
1 <dependencies> 2 <!--Junit--> 3 <dependency> 4 <groupId>junit</groupId> 5 <artifactId>junit</artifactId> 6 <version>4.12</version> 7 </dependency> 8 <!--数据库驱动--> 9 <dependency> 10 <groupId>mysql</groupId> 11 <artifactId>mysql-connector-java</artifactId> 12 <version>5.1.47</version> 13 </dependency> 14 <!-- 数据库连接池 --> 15 <dependency> 16 <groupId>com.mchange</groupId> 17 <artifactId>c3p0</artifactId> 18 <version>0.9.5.2</version> 19 </dependency> 20 21 <!--Servlet - JSP --> 22 <dependency> 23 <groupId>javax.servlet</groupId> 24 <artifactId>servlet-api</artifactId> 25 <version>2.5</version> 26 </dependency> 27 <dependency> 28 <groupId>javax.servlet.jsp</groupId> 29 <artifactId>jsp-api</artifactId> 30 <version>2.2</version> 31 </dependency> 32 <dependency> 33 <groupId>javax.servlet</groupId> 34 <artifactId>jstl</artifactId> 35 <version>1.2</version> 36 </dependency> 37 38 <!--Mybatis--> 39 <dependency> 40 <groupId>org.mybatis</groupId> 41 <artifactId>mybatis</artifactId> 42 <version>3.5.2</version> 43 </dependency> 44 <dependency> 45 <groupId>org.mybatis</groupId> 46 <artifactId>mybatis-spring</artifactId> 47 <version>2.0.2</version> 48 </dependency> 49 50 <!--Spring--> 51 <dependency> 52 <groupId>org.springframework</groupId> 53 <artifactId>spring-webmvc</artifactId> 54 <version>5.1.9.RELEASE</version> 55 </dependency> 56 <dependency> 57 <groupId>org.springframework</groupId> 58 <artifactId>spring-jdbc</artifactId> 59 <version>5.1.9.RELEASE</version> 60 </dependency> 61 </dependencies>
3、Maven资源过滤设置
1 <build> 2 <resources> 3 <resource> 4 <directory>src/main/java</directory> 5 <includes> 6 <include>**/*.properties</include> 7 <include>**/*.xml</include> 8 </includes> 9 <filtering>false</filtering> 10 </resource> 11 <resource> 12 <directory>src/main/resources</directory> 13 <includes> 14 <include>**/*.properties</include> 15 <include>**/*.xml</include> 16 </includes> 17 <filtering>false</filtering> 18 </resource> 19 </resources> 20 </build>
4、建立基本结构和配置框架!
-
com.kuang.pojo
-
com.kuang.dao
-
com.kuang.service
-
com.kuang.controller
-
mybatis-config.xml
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <configuration> 6 7 </configuration>
applicationContext.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7 </beans>
Mybatis层编写
1、数据库配置文件 database.properties
1 jdbc.driver=com.mysql.jdbc.Driver 2 jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8 3 jdbc.username=root 4 jdbc.password=123456
2、IDEA关联数据库
3、编写MyBatis的核心配置文件
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <configuration> 6 7 <typeAliases> 8 <package name="com.kuang.pojo"/> 9 </typeAliases> 10 <mappers> 11 <mapper resource="com/kuang/dao/BookMapper.xml"/> 12 </mappers> 13 14 </configuration>
4、编写数据库对应的实体类 com.kuang.pojo.Books
使用lombok插件!5、编写Dao层的 Mapper接口!
1 package com.kuang.pojo; 2 3 import lombok.AllArgsConstructor; 4 import lombok.Data; 5 import lombok.NoArgsConstructor; 6 7 @Data 8 @AllArgsConstructor 9 @NoArgsConstructor 10 public class Books { 11 12 private int bookID; 13 private String bookName; 14 private int bookCounts; 15 private String detail; 16 17 } 18 package com.kuang.dao; 19 20 import com.kuang.pojo.Books; 21 import java.util.List; 22 23 public interface BookMapper { 24 25 //增加一个Book 26 int addBook(Books book); 27 28 //根据id删除一个Book 29 int deleteBookById(int id); 30 31 //更新Book 32 int updateBook(Books books); 33 34 //根据id查询,返回一个Book 35 Books queryBookById(int id); 36 37 //查询全部Book,返回list集合 38 List<Books> queryAllBook(); 39 40 }
6、编写接口对应的 Mapper.xml 文件。需要导入MyBatis的包;
1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 6 <mapper namespace="com.kuang.dao.BookMapper"> 7 8 <!--增加一个Book--> 9 <insert id="addBook" parameterType="Books"> 10 insert into ssmbuild.books(bookName,bookCounts,detail) 11 values (#{bookName}, #{bookCounts}, #{detail}) 12 </insert> 13 14 <!--根据id删除一个Book--> 15 <delete id="deleteBookById" parameterType="int"> 16 delete from ssmbuild.books where bookID=#{bookID} 17 </delete> 18 19 <!--更新Book--> 20 <update id="updateBook" parameterType="Books"> 21 update ssmbuild.books 22 set bookName = #{bookName},bookCounts = #{bookCounts},detail = #{detail} 23 where bookID = #{bookID} 24 </update> 25 26 <!--根据id查询,返回一个Book--> 27 <select id="queryBookById" resultType="Books"> 28 select * from ssmbuild.books 29 where bookID = #{bookID} 30 </select> 31 32 <!--查询全部Book--> 33 <select id="queryAllBook" resultType="Books"> 34 SELECT * from ssmbuild.books 35 </select> 36 37 </mapper>
Spring层
1、配置Spring整合MyBatis,我们这里数据源使用c3p0连接池;
2、我们去编写Spring整合Mybatis的相关的配置文件;spring-dao.xml
spring整合mybatis : 这里面是读取配置文件里面的信息,然后配置连接池,配置sqlSessionFactory对象,配置扫描dao包
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context 8 https://www.springframework.org/schema/context/spring-context.xsd"> 9 10 <!-- 配置整合mybatis --> 11 <!-- 1.关联数据库文件 --> 12 <context:property-placeholder location="classpath:database.properties"/> 13 14 <!-- 2.数据库连接池 --> 15 <!--数据库连接池 16 dbcp 半自动化操作 不能自动连接 17 c3p0 自动化操作(自动的加载配置文件 并且设置到对象里面) 18 --> 19 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 20 <!-- 配置连接池属性 --> 21 <property name="driverClass" value="${jdbc.driver}"/> 22 <property name="jdbcUrl" value="${jdbc.url}"/> 23 <property name="user" value="${jdbc.username}"/> 24 <property name="password" value="${jdbc.password}"/> 25 26 <!-- c3p0连接池的私有属性 --> 27 <property name="maxPoolSize" value="30"/> 28 <property name="minPoolSize" value="10"/> 29 <!-- 关闭连接后不自动commit --> 30 <property name="autoCommitOnClose" value="false"/> 31 <!-- 获取连接超时时间 --> 32 <property name="checkoutTimeout" value="10000"/> 33 <!-- 当获取连接失败重试次数 --> 34 <property name="acquireRetryAttempts" value="2"/> 35 </bean> 36 37 <!-- 3.配置SqlSessionFactory对象 --> 38 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 39 <!-- 注入数据库连接池 --> 40 <property name="dataSource" ref="dataSource"/> 41 <!-- 配置MyBaties全局配置文件:mybatis-config.xml --> 42 <property name="configLocation" value="classpath:mybatis-config.xml"/> 43 </bean> 44 45 <!-- 4.配置扫描Dao接口包,动态实现Dao接口注入到spring容器中 --> 46 <!--解释 :https://www.cnblogs.com/jpfss/p/7799806.html--> 47 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 48 <!-- 注入sqlSessionFactory --> 49 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> 50 <!-- 给出需要扫描Dao接口包 --> 51 <property name="basePackage" value="com.kuang.dao"/> 52 </bean> 53 54 </beans>
spring整合service 这里配置扫描service层,然后配置事务,如果需要横切业务 也是在这里配置
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/context 8 http://www.springframework.org/schema/context/spring-context.xsd"> 9 10 <!-- 扫描service相关的bean --> 11 <context:component-scan base-package="com.kuang.service" /> 12 13 <!--BookServiceImpl注入到IOC容器中--> 14 <bean id="BookServiceImpl" class="com.kuang.service.BookServiceImpl"> 15 <property name="bookMapper" ref="bookMapper"/> 16 </bean> 17 18 <!-- 配置事务管理器 --> 19 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 20 <!-- 注入数据库连接池 --> 21 <property name="dataSource" ref="dataSource" /> 22 </bean> 23 24 </beans>
2、spring-mvc.xml 这里面配置注解驱动 配置 handel 配置视图解析器等。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:mvc="http://www.springframework.org/schema/mvc" 6 xsi:schemaLocation="http://www.springframework.org/schema/beans 7 http://www.springframework.org/schema/beans/spring-beans.xsd 8 http://www.springframework.org/schema/context 9 http://www.springframework.org/schema/context/spring-context.xsd 10 http://www.springframework.org/schema/mvc 11 https://www.springframework.org/schema/mvc/spring-mvc.xsd"> 12 13 <!-- 配置SpringMVC --> 14 <!-- 1.开启SpringMVC注解驱动 --> 15 <mvc:annotation-driven /> 16 <!-- 2.静态资源默认servlet配置--> 17 <mvc:default-servlet-handler/> 18 19 <!-- 3.配置jsp 显示ViewResolver视图解析器 --> 20 <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 21 <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> 22 <property name="prefix" value="/WEB-INF/jsp/" /> 23 <property name="suffix" value=".jsp" /> 24 </bean> 25 26 <!-- 4.扫描web相关的bean --> 27 <context:component-scan base-package="com.kuang.controller" /> 28 29 </beans>
3、Spring配置整合文件,applicationContext.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans 5 http://www.springframework.org/schema/beans/spring-beans.xsd"> 6 7 <import resource="spring-dao.xml"/> 8 <import resource="spring-service.xml"/> 9 <import resource="spring-mvc.xml"/> 10 11 </beans>
Spring层搞定!再次理解一下,Spring就是一个大杂烩,一个容器!对吧! 所以 spring可以整合mybatis(dao) , springMvc (controller) , service (service)
SpringMVC层
1、web.xml 这里加载 applicationContext.xml 然后配置 dispatcherServlet 还有 过滤器以及session 过期时间
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 5 version="4.0"> 6 7 <!--DispatcherServlet--> 8 <servlet> 9 <servlet-name>DispatcherServlet</servlet-name> 10 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 11 <init-param> 12 <param-name>contextConfigLocation</param-name> 13 <!--一定要注意:我们这里加载的是总的配置文件,之前被这里坑了!--> 14 <param-value>classpath:applicationContext.xml</param-value> 15 </init-param> 16 <load-on-startup>1</load-on-startup> 17 </servlet> 18 <servlet-mapping> 19 <servlet-name>DispatcherServlet</servlet-name> 20 <url-pattern>/</url-pattern> 21 </servlet-mapping> 22 23 <!--encodingFilter--> 24 <filter> 25 <filter-name>encodingFilter</filter-name> 26 <filter-class> 27 org.springframework.web.filter.CharacterEncodingFilter 28 </filter-class> 29 <init-param> 30 <param-name>encoding</param-name> 31 <param-value>utf-8</param-value> 32 </init-param> 33 </filter> 34 <filter-mapping> 35 <filter-name>encodingFilter</filter-name> 36 <url-pattern>/*</url-pattern> 37 </filter-mapping> 38 39 <!--Session过期时间--> 40 <session-config> 41 <session-timeout>15</session-timeout> 42 </session-config> 43 44 </web-app>
配置都完成后 接下来编写 Controller 层 增删改查 以及编写jsp前端页面。
1、BookController 类编写 , 方法一:查询全部书籍
1 @Controller 2 @RequestMapping("/book") 3 public class BookController { 4 5 @Autowired 6 @Qualifier("BookServiceImpl") 7 private BookService bookService; 8 9 @RequestMapping("/allBook") 10 public String list(Model model) { 11 List<Books> list = bookService.queryAllBook(); 12 model.addAttribute("list", list); 13 return "allBook"; 14 } 15 }
3、书籍列表页面 allbook.jsp
1 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 2 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 3 <html> 4 <head> 5 <title>书籍列表</title> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <!-- 引入 Bootstrap --> 8 <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> 9 </head> 10 <body> 11 12 <div class="container"> 13 14 <div class="row clearfix"> 15 <div class="col-md-12 column"> 16 <div class="page-header"> 17 <h1> 18 <small>书籍列表 —— 显示所有书籍</small> 19 </h1> 20 </div> 21 </div> 22 </div> 23 24 <div class="row"> 25 <div class="col-md-4 column"> 26 <a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toAddBook">新增</a> 27 </div> 28 </div> 29 30 <div class="row clearfix"> 31 <div class="col-md-12 column"> 32 <table class="table table-hover table-striped"> 33 <thead> 34 <tr> 35 <th>书籍编号</th> 36 <th>书籍名字</th> 37 <th>书籍数量</th> 38 <th>书籍详情</th> 39 <th>操作</th> 40 </tr> 41 </thead> 42 43 <tbody> 44 <c:forEach var="book" items="${requestScope.get('list')}"> 45 <tr> 46 <td>${book.getBookID()}</td> 47 <td>${book.getBookName()}</td> 48 <td>${book.getBookCounts()}</td> 49 <td>${book.getDetail()}</td> 50 <td> 51 <a href="${pageContext.request.contextPath}/book/toUpdateBook?id=${book.getBookID()}">更改</a> | 52 <a href="${pageContext.request.contextPath}/book/del/${book.getBookID()}">删除</a> 53 </td> 54 </tr> 55 </c:forEach> 56 </tbody> 57 </table> 58 </div> 59 </div> 60 </div>
案例整合ssm 到此结束 ,主要是熟悉 ssm 的文件的配置 spring整合 dao service controller web.xml 数据库配置文件 properties 中间的关系和配置。。
拦截器:
过滤器是servlet中的一部分,在web.xml中进行配置 针对所有的请求进行过滤
拦截器是springMvc中的,是基于反射,aop的一种体现 只对后台的请求地址有效 对前台的url无法进行拦截过滤
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。
过滤器与拦截器的区别:拦截器是AOP思想的具体应用。
过滤器
-
servlet规范中的一部分,任何java web工程都可以使用
-
在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截
拦截器
-
拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
-
拦截器只会拦截访问的控制器方法, 如果访问的是jsp/html/css/image/js是不会进行拦截的
自定义拦截器
那如何实现拦截器呢?
想要自定义拦截器,必须实现 HandlerInterceptor 接口。
1、新建一个Moudule , springmvc-07-Interceptor , 添加web支持
2、配置web.xml 和 springmvc-servlet.xml 文件
3、编写一个拦截器
1 package com.kuang.interceptor; 2 3 import org.springframework.web.servlet.HandlerInterceptor; 4 import org.springframework.web.servlet.ModelAndView; 5 6 import javax.servlet.http.HttpServletRequest; 7 import javax.servlet.http.HttpServletResponse; 8 9 public class MyInterceptor implements HandlerInterceptor { 10 11 //在请求处理的方法之前执行 12 //如果返回true执行下一个拦截器 13 //如果返回false就不执行下一个拦截器 14 public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { 15 System.out.println("------------处理前------------"); 16 return true; 17 } 18 19 //在请求处理方法执行之后执行 20 public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { 21 System.out.println("------------处理后------------"); 22 } 23 24 //在dispatcherServlet处理后执行,做清理工作. 25 public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { 26 System.out.println("------------清理------------"); 27 } 28 }
4、在springmvc的配置文件中配置拦截器
1 <!--关于拦截器的配置--> 2 <mvc:interceptors> 3 <mvc:interceptor> 4 <!--/** 包括路径及其子路径--> 5 <!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截--> 6 <!--/admin/** 拦截的是/admin/下的所有--> 7 <mvc:mapping path="/**"/> 8 <!--bean配置的就是拦截器--> 9 <bean class="com.kuang.interceptor.MyInterceptor"/> 10 </mvc:interceptor> 11 </mvc:interceptors>
5、编写一个Controller,接收请求
1 package com.kuang.controller; 2 3 import org.springframework.stereotype.Controller; 4 import org.springframework.web.bind.annotation.RequestMapping; 5 import org.springframework.web.bind.annotation.ResponseBody; 6 7 //测试拦截器的控制器 8 @Controller 9 public class InterceptorController { 10 11 @RequestMapping("/interceptor") 12 @ResponseBody 13 public String testFunction() { 14 System.out.println("控制器中的方法执行了"); 15 return "hello"; 16 } 17 }
6、前端 index.jsp
1 <a href="${pageContext.request.contextPath}/interceptor">拦截器测试</a>
验证用户是否登录 (认证用户)
实现思路
1、有一个登陆页面,需要写一个controller访问页面。
2、登陆页面有一提交表单的动作。需要在controller中处理。判断用户名密码是否正确。如果正确,向session中写入用户信息。返回登陆成功。
3、拦截用户请求,判断用户是否登陆。如果用户已经登陆。放行, 如果用户未登陆,跳转到登陆页面
编写一个Controller处理请求
1 package com.kuang.controller; 2 3 import org.springframework.stereotype.Controller; 4 import org.springframework.web.bind.annotation.RequestMapping; 5 6 import javax.servlet.http.HttpSession; 7 8 @Controller 9 @RequestMapping("/user") 10 public class UserController { 11 12 //跳转到登陆页面 13 @RequestMapping("/jumplogin") 14 public String jumpLogin() throws Exception { 15 return "login"; 16 } 17 18 //跳转到成功页面 19 @RequestMapping("/jumpSuccess") 20 public String jumpSuccess() throws Exception { 21 return "success"; 22 } 23 24 //登陆提交 25 @RequestMapping("/login") 26 public String login(HttpSession session, String username, String pwd) throws Exception { 27 // 向session记录用户身份信息 28 System.out.println("接收前端==="+username); 29 session.setAttribute("user", username); 30 return "success"; 31 } 32 33 //退出登陆 34 @RequestMapping("logout") 35 public String logout(HttpSession session) throws Exception { 36 // session 过期 37 session.invalidate(); 38 return "login"; 39 } 40 }
5、编写用户登录拦截器
1 package com.kuang.interceptor; 2 3 import org.springframework.web.servlet.HandlerInterceptor; 4 import org.springframework.web.servlet.ModelAndView; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 import javax.servlet.http.HttpSession; 10 import java.io.IOException; 11 12 public class LoginInterceptor implements HandlerInterceptor { 13 14 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException { 15 // 如果是登陆页面则放行 16 System.out.println("uri: " + request.getRequestURI()); 17 if (request.getRequestURI().contains("login")) { 18 return true; 19 } 20 21 HttpSession session = request.getSession(); 22 23 // 如果用户已登陆也放行 24 if(session.getAttribute("user") != null) { 25 return true; 26 } 27 28 // 用户没有登陆跳转到登陆页面 29 request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response); 30 return false; 31 } 32 33 public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { 34 35 } 36 37 public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { 38 39 } 40 }
6、在Springmvc的配置文件中注册拦截器
1 <!--关于拦截器的配置--> 2 <mvc:interceptors> 3 <mvc:interceptor> 4 <mvc:mapping path="/**"/> 5 <bean id="loginInterceptor" class="com.kuang.interceptor.LoginInterceptor"/> 6 </mvc:interceptor> 7 </mvc:interceptors>
文件上传和下载.
文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。
前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;
对表单中的 enctype 属性做个详细的说明:
-
application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。
-
multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
-
text/plain:除了把空格转换为 "+" 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
1 <form action="" enctype="multipart/form-data" method="post"> 2 <input type="file" name="file"/> 3 <input type="submit"> 4 </form>
一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。
-
Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。
-
而Spring MVC则提供了更简单的封装。
-
Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。
-
Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:
-
CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。
文件上传
1、导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;
1 <!--文件上传--> 2 <dependency> 3 <groupId>commons-fileupload</groupId> 4 <artifactId>commons-fileupload</artifactId> 5 <version>1.3.3</version> 6 </dependency> 7 <!--servlet-api导入高版本的--> 8 <dependency> 9 <groupId>javax.servlet</groupId> 10 <artifactId>javax.servlet-api</artifactId> 11 <version>4.0.1</version> 12 </dependency>
2、配置bean:multipartResolver
【注意!!!这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误!在这里栽过坑,教训!】
1 <!--文件上传配置--> 2 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 3 <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 --> 4 <property name="defaultEncoding" value="utf-8"/> 5 <!-- 上传文件大小上限,单位为字节(10485760=10M) --> 6 <property name="maxUploadSize" value="10485760"/> 7 <property name="maxInMemorySize" value="40960"/> 8 </bean>
CommonsMultipartFile 的 常用方法:
-
String getOriginalFilename():获取上传文件的原名
-
InputStream getInputStream():获取文件流
-
void transferTo(File dest):将上传文件保存到一个目录文件中
我们去实际测试一下
3、编写前端页面
1 <form action="/upload" enctype="multipart/form-data" method="post"> 2 <input type="file" name="file"/> 3 <input type="submit" value="upload"> 4 </form>
4、Controller
方式一:
1 package com.kuang.controller; 2 3 import org.springframework.stereotype.Controller; 4 import org.springframework.web.bind.annotation.RequestMapping; 5 import org.springframework.web.bind.annotation.RequestParam; 6 import org.springframework.web.multipart.commons.CommonsMultipartFile; 7 8 import javax.servlet.http.HttpServletRequest; 9 import java.io.*; 10 11 @Controller 12 public class FileController { 13 //@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象 14 //批量上传CommonsMultipartFile则为数组即可 15 @RequestMapping("/upload") 16 public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException { 17 18 //获取文件名 : file.getOriginalFilename(); 19 String uploadFileName = file.getOriginalFilename(); 20 21 //如果文件名为空,直接回到首页! 22 if ("".equals(uploadFileName)){ 23 return "redirect:/index.jsp"; 24 } 25 System.out.println("上传文件名 : "+uploadFileName); 26 27 //上传路径保存设置 28 String path = request.getServletContext().getRealPath("/upload"); 29 //如果路径不存在,创建一个 30 File realPath = new File(path); 31 if (!realPath.exists()){ 32 realPath.mkdir(); 33 } 34 System.out.println("上传文件保存地址:"+realPath); 35 36 InputStream is = file.getInputStream(); //文件输入流 37 OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流 38 39 //读取写出 40 int len=0; 41 byte[] buffer = new byte[1024]; 42 while ((len=is.read(buffer))!=-1){ 43 os.write(buffer,0,len); 44 os.flush(); 45 } 46 os.close(); 47 is.close(); 48 return "redirect:/index.jsp"; 49 } 50 }
方式二:
采用file.Transto 来保存上传的文件
1、编写Controller
1 /* 2 * 采用file.Transto 来保存上传的文件 3 */ 4 @RequestMapping("/upload2") 5 public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException { 6 7 //上传路径保存设置 8 String path = request.getServletContext().getRealPath("/upload"); 9 File realPath = new File(path); 10 if (!realPath.exists()){ 11 realPath.mkdir(); 12 } 13 //上传文件地址 14 System.out.println("上传文件保存地址:"+realPath); 15 16 //通过CommonsMultipartFile的方法直接写文件(注意这个时候) 17 file.transferTo(new File(realPath +"/"+ file.getOriginalFilename())); 18 19 return "redirect:/index.jsp"; 20 }
文件下载
文件下载步骤:
1、设置 response 响应头
2、读取文件 -- InputStream
3、写出文件 -- OutputStream
4、执行操作
5、关闭流 (先开后关)
代码实现:
controller: 这里的 基础语法.jpg 图片需要放在项目目录里面
1 @RequestMapping(value="/download") 2 public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{ 3 //要下载的图片地址 4 String path = request.getServletContext().getRealPath("/upload"); 5 String fileName = "基础语法.jpg"; 6 7 //1、设置response 响应头 8 response.reset(); //设置页面不缓存,清空buffer 9 response.setCharacterEncoding("UTF-8"); //字符编码 10 response.setContentType("multipart/form-data"); //二进制传输数据 11 //设置响应头 12 response.setHeader("Content-Disposition", 13 "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8")); 14 15 File file = new File(path,fileName); 16 //2、 读取文件--输入流 17 InputStream input=new FileInputStream(file); 18 //3、 写出文件--输出流 19 OutputStream out = response.getOutputStream(); 20 21 byte[] buff =new byte[1024]; 22 int index=0; 23 //4、执行 写出操作 24 while((index= input.read(buff))!= -1){ 25 out.write(buff, 0, index); 26 out.flush(); 27 } 28 out.close(); 29 input.close(); 30 return null; 31 }
前端:
1 <a href="/download">点击下载</a>

浙公网安备 33010602011771号