springmvc学习
SpringMVC
一.MVC(回顾)
1.什么是MVC
- MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范
2.MVC知识点梳理
- 每个模对应的知识点====>模型(dao、pojo、service)、视图(jsp、html)、控制器(Servlet)
- MVC是将业务逻辑、数据、显示分离的方法来组织代码
- pojo层用来编写数据库的实体类,dao层连接数据库,service层调用dao层执行具体业务,jsp、html前端页面
- servlet:接收前端的数据,将数据交给service层后端处理,service层返回的结果转到要控制的页面,跳转到页面(重点:转发和重定向)
3.MVC的作用
- MVC主要作用是降低了视图与业务逻辑间的双向偶合。
- MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。
4.web项目架构的发展
4.1 Model1时代
- 在web早期的开发中,通常采用的都是Model1。
- Model1中,主要分为两层,视图层和模型层。
- 这个模式下 JSP 既是控制层又是视图层。显而易见,这种模式存在很多问题。比如①将控制逻辑和表现逻辑混杂在一起,导致代码重用率极低;②前端和后端相互依赖,难以进行测试并且开发效率极低;
-
Model1优点:架构简单,比较适合小型项目开发;
-
Model1缺点:JSP职责不单一,职责过重,不便于维护;
4.2.Model2时代
- Model2把一个项目分成三部分,包括视图、控制、模型。
- 用户发请求
- Servlet接收请求数据,并调用对应的业务逻辑方法
- 业务处理完毕,返回更新后的数据给servlet
- servlet转向到JSP,由JSP来渲染页面
- 响应给前端更新后的页面
-
职责分析:
-
Controller:控制器
- 取得表单数据
- 调用业务逻辑
- 将业务保存测数据,发送、转向指定的页面
Model:模型
- 业务逻辑
- 保存数据的状态
View:视图
- 显示页面,展示模型层中保存的数据
-
-
优缺点分析
- Model2这样不仅提高的代码的复用率与项目的扩展性,且大大降低了项目的维护成本。Model 1模式的实现比较简单,适用于快速开发小规模项目,Model1中JSP页面身兼View和Controller两种角色,将控制逻辑和表现逻辑混杂在一起,从而导致代码的重用性非常低,增加了应用的扩展性和维护的难度。Model2消除了Model1的缺点。
MVC 是一种设计模式,Spring MVC 是一款很优秀的 MVC 框架。
二.Servlet(回顾)
1.创建一个Servlet程序的步骤
- 开发一个Servlet程序,只需要完成两个小步骤
- 编写一个类,来实现Servlet接口
- 把开发好的Java类部署到Web服务器如Tomcat中
2.创建一个Servlet程序
-
1)创建一个Maven父工程,删除src文件夹,在pom中导入所需依赖和解决资源无法导出的问题
<dependencies> <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>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>jstl</artifactId> <version>1.2</version> </dependency> </dependencies> <!--在bulid中配置resources,来防止我们资源导出失败的问题--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
-
2)然后创建一个子Maven-web项目,之前是以一个为模板创造,但是需要修改web的配置,此处用另外一种方式创建
-
创建一个普通的子Maven项目
-
然后点击如下
-
-
3)(可以省略)在子项目的pom文件中导入相关的依赖(父项目的前面两个)
-
4)编写一个Servlet类,用来处理用户的请求(此处写一个HelloServlet)
public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1、获取前端数据 String method=req.getParameter("method"); if(method.equals("add")){ req.getSession().setAttribute("msg","执行了add方法"); } if(method.equals("delete")){ req.getSession().setAttribute("msg","执行了delete方法"); } //2、调用业务层 //3、视图转发或者进行重定向 //请求转发,获取的路径,不用加服务器(Tomcat)配置的站点名, req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
**回顾知识: **
1.req.getParameter获取前端传递的参数
2.request.setAttribute()和request.getSession().setAttribute()
- request.setAttribute()只能在一个request内有效,如果重定向客户端,将取不到值。
- request.getSession().setAttribute()可以通过sessionID得到自己的session,将参数存储在session中,即使重定向客户端也没事,这个值可以在多个页面上使用。
- 比如访问一个网站,登录后用户信息被保存到session中,在session过期之前或者用户关闭页面之前,用户信息可以通过request.getSession().getAttribute()方式 获得。
- request在当次的请求的URL之间有效,比如,你在请求某个servlet,那么你提交的信息,可以使用request.getAttribute()方式获得,而当你再次跳转之后,这些信息将不存在。
3.setAttribute("msg","执行了add方法")类似与键值对的形式,当在前端访问${msg},便会打印后面的值
-
5)新建一个上面HelloSevlet请求转发的页面或者重定向的页面(这里为请求转发的页面)
编写hello.jsp,在WEB-INF目录下新建一个jsp的文件夹,新建hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>hello</title> </head> <body> ${msg} </body> </html>
-
6)在web.xml中注册Servlet
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.lyj.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <!--欢迎页,默认为index.jsp--> <welcome-file-list> <welcome-file>form.jsp</welcome-file> </welcome-file-list>
-
7)用表单去提交请求的页面(新建一个form.jsp页面)
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>HelloServlet</title> </head> <body> <form action="/hello" method="post"> <input type="text" name="method"> <input type="submit"> </form> </body> </html>
-
8)利用Tomcat配置web项目
-
9)测试
在浏览器输入:http://localhost:8080/springmvc-servlet/可以访问欢迎页form.jsp的页面
在浏览器输入:http://localhost:8080/springmvc-servlet/hello?method=add可以请求跳转到hello.jsp的页面
3.MVC框架要做哪些事情
-
将url映射到java类或java类的方法 .
-
封装用户提交的数据 .
-
处理请求--调用相关的业务处理--封装响应数据
-
将响应的数据进行渲染 . jsp / html 等表示层数据
三.初识SpringMVC
1.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
2.springmvc特点
-
轻量级,简单易学
-
高效 , 基于请求响应的MVC框架(处理http的请求然后返回一个视图)
-
与Spring兼容性好,无缝结合(可以将springmvc所有要用到的bean全部注册到spring中)
-
约定优于配置
-
功能强大:RESTful、数据验证、格式化、本地化、主题等
-
简洁灵活
3.springmvc框架的中心控制器DispatcherServlet
-
Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)。
-
Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计。
-
DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解形式进行开发,十分简洁;
4.第一个体现springmvc框架的spring程序的搭建:hellospringmvc
-
1)新建一个子Moudle , spring-02-hellospringmvc , 添加web的支持!
-
2)确定导入了SpringMVC 的依赖!(前面在父工程已经导入)
-
3)配置web.xml , 注册DispatcherServlet(之前是注册继承了HttpServlet的类)
<?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)--> <!--一般不用,防止出现a.jsp.jsp的嵌套(视图解析器拼接.jsp后缀)“/*” 匹配所有的请求;(包括.jsp)--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
此处相当于,我们所有的请求都会先经过这个DispatcherServlet,然后里面关联了一个springmvc的配置文件
-
4)因为在web.xml中关联了一个springmvc的配置文件,所以此处需要:编写SpringMVC 的 配置文件!名称:springmvc-servlet.xml : [servletname]-servlet.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans>
-
5)在springmvc的配置文件中
-
添加 url处理器映射器
-
添加 url处理器适配器
-
添加 视图解析器
<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>
-
-
6)编写我们要操作业务Controller ,要么实现Controller接口,要么增加注解;需要返回一个ModelAndView,装数据,封视图;
public class HelloController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //ModelAndView 模型和视图 ModelAndView mv = new ModelAndView(); //处理业务 String result="HelloSpringMVC!"; //封装对象,放在ModelAndView的Model中 mv.addObject("msg",result); //封装要跳转的视图,放在ModelAndView中 mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp return mv; } }
以前存放数据,需要通过requset或者session的setAttribute方法,现在可以通过 ModelAndView.addObject方法,以前要跳转页面或者重定向,现在可以直接跳转视图通过: ModelAndView.setViewName
-
7)创建好需要跳转的视图:/WEB-INF/jsp/hello.jsp文件,并显示ModelandView存放的数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${msg} </body> </html>
-
8)将自己的操作业务的类HelloController交给SpringIOC容器(SpringMVC 的 配置文件:springmvc-servlet.xml ),注册bean
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> <!--视图解析器:DispatcherServlet给他的ModelAndView--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后缀--> <property name="suffix" value=".jsp"/> </bean> <!--Handler--> <bean id="/hellomvc" class="com.lyj.controller.HelloController"/> </beans>
注意:添加了的url处理映射器和url处理器适配器的作用是: 浏览器访问的路径url去匹配我们的spring中的Handler控制器(处理器),这里使用的是BeanNameUrlHandlerMapping,通过bean匹配,看有哪个bean_id与这个访问路径相匹配,就用哪个controller处理它(执行原理见三.5)
-
9)配置Tomcat 启动测试!(Tomcat服务器上配置的web站点为:hellospringmvc)
-
可能遇到的问题:访问出现404,排查步骤:
- 查看控制台输出,看一下是不是缺少了什么jar包。
- 如果jar包存在,显示无法输出,就在IDEA的项目发布中,添加lib依赖!
- 重启Tomcat 即可解决!
-
5.springmvc执行原理
5.1 springmvc简单原理
- Spring MVC 下我们一般把后端项目分为 Service层(处理业务)、Dao层(数据库操作)、Entity层(实体类)、Controller层(控制层,返回数据给前台页面)。
Spring MVC 简单的工作原理图如下:
5.2 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被查找处理器为:hello。
-
HandlerExecution将解析后的信息(如:生成处理器对象及处理器拦截器,解析控制器映射等)传递给DispatcherServlet。
)))))
-
DispatcherServlet调用HandlerAdapter处理器适配器(接口),其作用是:按照特定的规则去执行Handler,找到具体的Controller去执行该处理器
-
Handler让具体的Controller执行,并处理相应的业务。通过HandlerAdapter对处理器进行执行, 经过适配调用得到具体的处理器(Controller,也叫后端控制器)。
-
Controller将具体的执行信息(如:ModelAndView对象,需要返回给前端的数据,跳转的页面等)返回给HandlerAdapter。(后面controller还可以调用业务层)
-
HandlerAdapter又将ModelAndView 对象(包含模型数据、逻辑视图名)传递给DispatcherServlet。
-
DispatcherServlet获取了ModelAndView,调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。(解析ModelAndView的视图名字,解析的方式可以有拼接视图名等)
Model
是返回的数据对象,View
是个逻辑上的View
。ViewResolver
会根据逻辑View
查找实际的View
。DispaterServlet
把返回的Model
传给View
(视图渲染)。- 把
View
返回给请求者(浏览器)
-
视图解析器将解析后的逻辑视图名传给DispatcherServlet。
-
DispatcherServlet根据视图解析器解析的视图结果,将数据渲染到视图上,调用具体的视图。
-
最终视图呈现给用户。
6.利用注解开发具有springmvc框架的spring程序
-
1)新建一个Moudle,spring-03-hello-annotation 。添加web支持!
-
2)确认导入springmvc的依赖,在pom.xml文件引入相关的依赖:主要有Spring框架核心库、Spring MVC、servlet , JSTL等。我们在父依赖中已经引入了!
-
3)添加lib文件,导入jar包(解决前面出现404的问题)
-
4)配置web.xml
- 注意web.xml版本问题,要最新版!
- 注册DispatcherServlet
- 关联SpringMVC的配置文件
- 启动级别为1
- 映射路径为 / 【不要用/*,会404】
?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)--> <!--一般不用,防止出现a.jsp.jsp的嵌套(视图解析器拼接.jsp后缀)“/*” 匹配所有的请求;(包括.jsp)--> <!--所有请求都会被springmvc所拦截!!--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
-
/ 和 /* 的区别:< url-pattern > / </ url-pattern > 不会匹配到.jsp, 只针对我们编写的请求;即:.jsp 不会进入spring的 DispatcherServlet类 。< url-pattern > /* </ url-pattern > 会匹配 *.jsp,会出现返回 jsp视图 时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。
-
5)添加Spring MVC配置文件(在resources目录下创建,命名为:springmvc-servlet.xml)
-
因为为注解开发,相对于普通的spring,要添加一些其他的约束(context,mvc)
-
利用context设置自动扫描包让包内的所有注解生效
-
里面mvc设置不处理静态资源,以及自动注入处理器映射和处理器适配的实例
-
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的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.lyj.controller"/> <context:annotation-config/> <!-- 让Spring MVC不处理静态资源,让.css .js .html .mp3 .mp4文件过滤 --> <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>
-
-
6)创建Controller(此处创建一个名为HelloController的类),利用注解完成
@Controller @RequestMapping("/annotation") public class HelloController { @RequestMapping("/hello") public String helloAnnotation(Model model){ //真实访问地址 : web站点名/annotation/hello //向模型中添加属性msg与值,可以在JSP页面中取出并渲染 model.addAttribute("msg","hello,springmvc,annotation"); //WEB-INF/jsp/hello.jsp return "hello"; } }
- @Controller是为了让Spring IOC容器初始化时自动扫描到;
- @RequestMapping是为了映射请求路径,这里因为类与方法上都有映射所以访问时应该是/web站点名/annotation/hello;
- 方法中声明Model类型的参数是为了把Action中的数据带到视图中;
- 方法返回的结果是视图的名称hello,加上配置文件中的前后缀变成WEB-INF/jsp/hello.jsp。
-
7)创建返回的视图WEB-INF/jsp/hello.jsp
-
视图可以直接取出并展示从Controller带回的信息;
-
可以通过EL表示取出Model中存放的值,或者对象;
-
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${msg} </body> </html>
-
-
8)配置Tomcat并测试(tomcat配置的web站点名为:hellospringmvcAnnotation)
四.springmvc的控制器(Controller)
- Controller(控制器)负责解析用户的请求并将其转换为一个模型。
- Controller(控制器)负责提供访问应用程序的行为,通常通过接口定义或注解定义两种方法实现
1.通过接口定义实现Controller(如:见三.4第一个springmvc)
-
web.xml不变,springmvc的配置文件springmvc-servlet.xml大致不变,可以不用添加处理器映射和处理器适配(默认的)
-
编写一个类,来实现Controller接口(类名Controller1),重新接口方法,将用户请求转换为模型
public class Controller1 implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("msg","Controller1"); modelAndView.setViewName("test"); return modelAndView; } }
-
编写完毕后,去Spring配置文件中注册请求的bean;name对应请求路径,class对应处理请求的类
<bean name="/t1" class="com.lyj.controller.Controller1"/>
-
编写前端test.jsp,注意在WEB-INF/jsp目录下编写,对应我们的视图解析器
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Kuangshen</title> </head> <body> ${msg} </body> </html>
-
配置Tomcat,测试(配置的web站点名为springmvcController)
缺点是:一个控制器中只有一个方法,如果要多个方法则需要定义多个Controller;定义的方式比较麻烦;
2.使用注解定义方式实现Controller(见三.6利用注解开发springmvc)
= = = = = = = = = = = = = = = = = = = == = == = = = = = = = == = = = = = = = = = = = = = = =
-
@Component:将这个注解放在类上,意味着这个类被Spring管理,会自己装配bean
-
@Component有几个衍生注解,在WEB开发中,会按照MVC三层架构用在不同的层之中
- dao【@Repository】
- service【@Service】
- controller【@Controller】
= = = = = = = = = = = = = = = = = = = == = == = = = = = = = == = = = = = = = = = = = = = = =
-
@Controller注解:用于声明这个类被spring接管,是一个控制器
-
被其注解的类中,所有的方法,如果返回值是String,并且返回的值(名字),有具体的页面可以跳转,那么它就会自动被视图解析器解析
-
Spring可以使用扫描机制来找到应用程序中所有基于注解的类(包括我们所需的控制类),为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描。
<!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --> <context:component-scan base-package="com.kuang.controller"/>
-
增加一个Controller2类,使用注解实现;
@Controller public class Controller2 { @RequestMapping("/t2") public String test2(Model model){ model.addAttribute("msg","controller2"); return "test"; } @RequestMapping("/t3") public String test3(Model model){ model.addAttribute("msg","controller3"); return "test"; } }
-
配置Tomcat,测试(配置的web站点名为springmvcController)
可以发现,一个控制器可以有多个方法,我们的两个请求都可以指向一个视图,但是页面结果的结果是不一样的,从这里可以看出视图是被复用的,而控制器与视图之间是弱偶合关系。
3.@RequestMapping
- @RequestMapping注解用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。(见三.6利用注解开发springmvc)
五.springmvc的RestFul 风格
1.RestFul 风格的基本概念
-
资源:互联网所有的事物都可以被抽象为资源
-
资源操作:使用POST(添加)、DELETE(删除)、PUT(修改)、GET(查询),使用不同方法对资源进行操作。
-
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
2.传统方式操作资源和RestFul操作资源的区别
-
传统方式操作资源 :通过不同的参数来实现不同的效果!方法单一,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
3. 新建一个类,用传统方式操作资源
@Controller
public class ControllerRestFul {
@RequestMapping("/restful")
public String testRestFul1(int a, String b, Model model){
String result=a+b;
model.addAttribute("msg","结果1为:"+result);
return "test";
}
}
-
配置Tomcat进行测试(配置的web站点名为:springmvcController)
-
浏览器输入:http://localhost:8080/springmvcController/restful?a=100&b=lyj
4.在上述类中,新建方法,RestFul风格化操作资源
-
Spring MVC 的 @RequestMapping 注解能够处理 HTTP 请求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH。
-
在Spring MVC中可以使用 @PathVariable 注解,让方法参数的值对应绑定到一个URI模板变量上。
-
使用method属性指定请求类型,我们使用浏览器地址栏进行访问默认是Get请求
-
4.1)GET请求
-
@Controller public class ControllerRestFul { @RequestMapping(value = "/restful/{a}/{b}",method = RequestMethod.GET) public String testRestFul2(@PathVariable int a, @PathVariable String b, Model model){ String result=a+b; model.addAttribute("msg","结果2为:"+result); return "test"; } }
-
配置Tomcat进行测试(配置的web站点名为:springmvcController)
-
浏览器输入:http://localhost:8080/springmvcController/restful/100/lyj
-
如果上面的请求方法变为post方法,浏览器输入:http://localhost:8080/springmvcController/restful?a=100&b=lyj
则会出现下面的405请求方法错误
@RequestMapping(value = "/restful/{a}/{b}",method = RequestMethod.POST)
-
-
-
4.2)post请求
-
@Controller public class ControllerRestFul { @RequestMapping(value = "/restful/{a}/{b}",method = RequestMethod.POST) public String testRestFul3(@PathVariable int a, @PathVariable String b, Model model){ String result=a+b; model.addAttribute("msg","结果3为:"+result); return "test"; } }
- 由于浏览器默认的请求方式是GET方法,所以要用表单,post方式提交请求,在web中新建一个form.jsp表单,表单用post方式提交
-
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form action="/springmvcController/restful/1/2" method="post"> <input type="text" name="a"> <input type="text" name="b"> <input type="submit"> </form> </body> </html>
-
配置Tomcat进行测试(配置的web站点名为:springmvcController)注意上面的表单action必须写上配置的web站点名,否则请求不到该项目
-
点击提交:自动跳转到如下
-
-
-
4.3)组合注解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@GetMapping 是一个组合注解,平时使用的会比较多!
它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一个快捷方式。
@GetMapping("/restful/{a}/{b}")
//@RequestMapping(value = "/restful/{a}/{b}",method = RequestMethod.GET)
//两者等效!!!!
六.springmvc的跳转方式
1.视图解析器ModelAndView
设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面 .
页面 : {视图解析器前缀} + viewName +{视图解析器后缀}
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
- 前面用了两种方式得到view的名称
- 未使用注解开发,通过创建继承接口Controller的类,设置ModelAndView对象,通过该对象的setViewName方法,得到跳转的图像名,然后与视图解析器解析拼接
- 使用注解开发,被@Controller注解的类中,所有的方法,如果返回值是String,并且返回的值(名字),那么这个值就会自动被视图解析器解析拼接
2.回顾Servlet的重定向和请求转发
-
新建一个新的类,不需要视图解析器,用Servlet的对象完成如下操作
-
通过HttpServletResponse进行输出
-
通过HttpServletResponse实现重定向
-
通过HttpServletResponse实现转发
-
@Controller public class ControllerServlet { @RequestMapping("/result/t1") public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException { rsp.getWriter().println("Hello,Spring BY servlet API"); } @RequestMapping("/result/t2") public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException { rsp.sendRedirect("/springmvcController/form.jsp"); } @RequestMapping("/result/t3") public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception { //转发 req.setAttribute("msg","请求转发"); req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp); } }
-
配置Tomcat进行测试(配置的web站点名为:springmvcController)
-
注意1:此处的重定向,获取的路径必须加上 web服务器(Tomcat)配置的站点名springmvcController,因为它的地址栏会变化,所以要指明跳转的web项目名,而后面的form.jsp是在web上面本来就有的路径名,否则会找不到。重定向的路径为:/springmvcController/form.jsp
重定向不能访问WEB-INF下的资源!!!!,而请求转发可以
注意2:而请求转发,获取的路径,不用加服务器(Tomcat)配置的站点名,因为它的地址栏不会变化,只是在自己访问的web项目里面,请求转发其他路径的数据,页面显示请求转发路径里面的数据。请求转发的路径名为:/WEB-INF/jsp/test.jsp
-
3.springmvc的重定向和请求转发
-
3.1)不使用视图解析器
-
@Controller public class ResultSpringMVC { @RequestMapping("/rsm/t1") public String test1(){ //转发 return "/WEB-INF/jsp/hello.jsp"; } @RequestMapping("/rsm/t2") public String test2(){ //转发二 return "forward:/WEB-INF/jsp/hello.jsp"; } @RequestMapping("/rsm/t3") public String test3(){ //重定向 return "redirect:/index.jsp"; } }
-
-
3.2)使用视图解析器
-
@Controller public class ResultSpringMVC2 { @RequestMapping("/rsm2/t1") public String test1(Model model){ //转发 model.addAttribute("msg","springmvc的请求转发"); return "test"; } @RequestMapping("/rsm2/t2") public String test2(){ //重定向 return "redirect:/index.jsp"; } }
注意1:这里的重定向不走视图解析器,所以需要加具体路径,且重定向不能访问WEB-INF下的资源
注意2:虽然这里的重定向不能走WEB-INF下的资源,但是可以通过"redirect:/rsm2/t1"访问到WEB-INF下的资源
注意3:这里的重定向的路径,不需要向上面Servlet的重定向+一个配置的web站点名/springmvcController
-
配置Tomcat进行测试(配置的web站点名为:springmvcController)
-
七.springmvc前端数据处理
1.处理前端提交的数据
-
在Servlet程序的时候,使用req.getParameter获取前端的数据(见二.Servlet的回顾)
-
在springmvc可以通过方法参数,得到想要的前端提交的数据
-
注意:如果前端想要提交的是一个对象,要求提交的前端参数必须和对象的属性名一致 ,后端方法中的参数使用对象即可
- 前端传递的参数名和对象名必须一致,否则就是null。
- 前端如果没有传递的,返回的是null
-
@Controller @RequestMapping("/user") public class DataSpringMVC { @GetMapping("/t1") //http://localhost:8080/springmvcController/user/t1?name=xxx public String test1(String name){ //1.获取前端参数 //2.对前端的参数进行打印 System.out.println(name); return "hello"; } @GetMapping("/t2") //http://localhost:8080/springmvcController/user/t2?username=xxx public String test2(@RequestParam("username")String name){ //1.获取前端参数 //2.对前端的参数进行打印 System.out.println(name); return "hello"; } @GetMapping("/t3") //http://localhost:8080/springmvcController/user/t3?id=xx&name=xxx&age=xx public String test3(User user){ //1.获取前端参数 //2.对前端的参数进行打印 System.out.println(user); return "hello"; }
-
配置Tomcat进行测试(配置的web站点名为:springmvcController)
-
在浏览器输入:http://localhost:8080/springmvcController/user/t1?name=lyj
- 前端跳转至hello的页面,后端打印lyj
-
在浏览器输入:http://localhost:8080/springmvcController/user/t2?name=lyj
- 错误的请求,出现400,因为参数名必须是username
-
在浏览器输入:http://localhost:8080/springmvcController/user/t2?username=lyj
- 前端跳转至hello的页面,后端打印lyj
-
在浏览器输入:http://localhost:8080/springmvcController/user/t3?id=1&age=21
- 前端跳转至hello的页面,后端打印User
-
在浏览器输入:http://localhost:8080/springmvcController/user/t3?userid=1&name=lyj&age=21
- 前端跳转至hello的页面,后端打印User
-
2.将数据显示到前端
-
第一种 : 通过ModelAndView
我们前面一直都是如此 . 就不过多解释
public class ControllerTest1 implements Controller { public ModelAndView handleRequest(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws Exception { //返回一个模型视图对象 ModelAndView mv = new ModelAndView(); mv.addObject("msg","ControllerTest1"); mv.setViewName("test"); return mv; } }
第二种 : 通过ModelMap
ModelMap
@RequestMapping("/hello") public String hello(@RequestParam("username") String name, ModelMap model){ //封装要显示到视图中的数据 //相当于req.setAttribute("name",name); model.addAttribute("name",name); System.out.println(name); return "hello"; }
第三种 : 通过Model
Model
@RequestMapping("/ct2/hello") public String hello(@RequestParam("username") String name, Model model){ //封装要显示到视图中的数据 //相当于req.setAttribute("name",name); model.addAttribute("msg",name); System.out.println(name); return "test"; }
对比
就对于新手而言简单来说使用区别就是:
Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解; ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性; ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
八.解决乱码问题
- 解决前端请求的数据为中文,提取到后端为乱码
- 解决后端的数据为中文,发送到前端为乱码
1.Servlet解决乱码的操作
//设置浏览器(客户端)响应的格式,让发出的文档可以显示
resp.setContentType("text/html;charset=utf-8");
//解决后台接收中文数据乱码的问题
req.setCharacterEncoding("utf-8");
//解决客户端显示的中文数据为乱码的问题
resp.setCharacterEncoding("utf-8");
2.springmvc中文乱码的情况
-
新建一个类
-
@Controller @RequestMapping("/encoding") public class EncodingController { @PostMapping("/t") public String main(Model model, @RequestParam("username") String name){ System.out.println(name); model.addAttribute("msg",name); return "test"; } }
由于是提交请求的方法是post,所以要建一个form2.jsp表单用post方式提交
-
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form action="/springmvcController/encoding/t" method="post"> <input type="text" name="username"> <input type="submit"> </form> </body> </html>
注意:由于上面请求的参数名为username,所以填写前端数据的text的name也要为username,否则会出现400错误,请求出错: Required String parameter 'username' is not present
-
配置Tomcat进行测试(配置的web站点名为:springmvcController)
-
浏览器输入:林煜钧,点击提交
-
浏览器的路径变为:http://localhost:8080/springmvcController/encoding/t但是显示的页面是test.jsp页面
前端,后端输出都为乱码
3.springmvc解决乱码的操作
-
SpringMVC给我们提供了一个过滤器 , 可以在web.xml中配置 .
修改了xml文件然后重启服务器进行测试!
<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>
-
注意: 上面跳转的页面是test.jsp,
/* 是处理包括.jsp的文件
九.JSON
1.什么是JSON
- JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛。
- 采用完全独立于编程语言的文本格式来存储和表示数据。
- 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
- 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
2.JSON的一些简单的语法
-
JSON 键值对是用来保存 JavaScript 对象的一种方式,和 JavaScript 对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 "" 包裹,使用冒号 : 分隔,然后紧接着值:
{"name": "QinJiang"} {"age": "3"} {"sex": "男"}
-
JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的 var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串
-
JSON 和 JavaScript 对象互转
要实现从JSON字符串转换为JavaScript 对象,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}'); //结果是 {a: 'Hello', b: 'World'}
要实现从JavaScript 对象转换为JSON字符串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'}); //结果是 '{"a": "Hello", "b": "World"}'
3.Jackson的使用
利用Controll返回J前端JSON格式的数据
-
1)新建一个子Maven项目spring-05-json,添加web的支持
-
2)确认在.pom文件中导入相关依赖----之前父项目已经添加,此处需要增加一个jackson-databind依赖
-
<dependencies> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.2</version> </dependency> </dependencies>
-
-
3)配置web.xml,加上上面的解决乱码的springmvc的过滤器(见上)
-
4)添加Spring MVC配置文件(在resources目录下创建,命名为:springmvc-servlet.xml)(见上)
-
5)添加lib文件,导入jar包(解决前面出现404的问题)
-
6)新建一个User的实体类,然后用我们的Controller去创建这个对象,然后在前端利用JSON格式返回数据
-
//写好get/set方法,无参、有参构造,以及toString方法 public class User { private String name; private int age; private String sex; }
-
@Controller public class UserController { @RequestMapping("/json1") @ResponseBody public String json1() throws JsonProcessingException { //创建一个jackson的对象映射器,用来解析数据 ObjectMapper mapper = new ObjectMapper(); //创建一个对象 User user = new User("lyj", 3, "男"); //将我们的对象解析成为json格式 String str = mapper.writeValueAsString(user); //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便 return str; } } //在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody !我们在前后端分离开发中,一般都使用
-
注意1:此处 @ResponseBody的用法是:让下面的方法不走视图解析器,而是返回一个字符串.
-
注意2:此处的ObjectMapper是JSON包下面的一个对象,利用该对象的writeValueAsString()方法将值转成字符串的形式
-
注意3:由于不走视图解析器,所以页面不会进行跳转,将字符串输出到,当前页面,所以出现的中文乱码问题,就不会经过之前在web.xml上配置的springmvc的过滤器,得在springmvc的配置文件内添加一段消息StringHttpMessageConverter转换配置
-
<?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.lyj.controller"/> <context:annotation-config/> <!-- 让Spring MVC不处理静态资源 --> <mvc:default-servlet-handler /> <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> <!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> </bean> </beans>
-
-
-
7)配置Tomcat,进行测试(配置的web站点名为springmvcJson)
-
8)利用这种方式,还可以在前端利用JSON格式返回多个对象数据(利用集合)
-
@RestController public class UserController { @RequestMapping("/json2") public String json2() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); User user1 = new User("lyj1", 1, "男"); User user2 = new User("lyj2", 2, "男"); User user3 = new User("lyj3", 3, "男"); User user4 = new User("lyj4", 4, "男"); List<User> list = new ArrayList<User>(); list.add(user1); list.add(user2); list.add(user3); list.add(user4); String str = mapper.writeValueAsString(list); //将我们的对象解析成为json格式 return str; } }
-
-
9)在UserController类中新增一个方法(在前端中,利用Json格式返回时间)
-
Jackson 默认是会把时间转成timestamps形式(默认日期格式会变成一个数字,是1970年1月1日到当前日期的毫秒数),所以我们需要:取消timestamps形式 , 自定义时间格式
-
@RequestMapping("/json3") 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");//HH是24h制,hh是12h制 //指定日期格式 mapper.setDateFormat(sdf); Date date = new Date(); String str = mapper.writeValueAsString(date); return str; }
-
配置Tomcat,进行测试(配置的web站点名为springmvcJson)
-
-
10)如果要经常使用的话,这样是比较麻烦的,我们可以将这些代码封装到一个工具类JsonDateUtils中(放在utils包中)
-
- 一种思想!!!!!!
- 这里的两个getJson的方法作用是相同的,只是其中之一缺少了一个参数,于是用如下的方式进行调用
-
public class JsonDateUtils { public static String getJson(Object object) { return getJson(object,"yyyy-MM-dd HH:mm:ss"); } public static String getJson(Object object,String dateFormat) { ObjectMapper mapper = new ObjectMapper(); //不使用时间差的方式 mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); //自定义日期格式对象 SimpleDateFormat sdf = new SimpleDateFormat(dateFormat); //指定日期格式 mapper.setDateFormat(sdf); try { return mapper.writeValueAsString(object); } catch (JsonProcessingException e) { e.printStackTrace(); } return null; } }
-
@RequestMapping("/json4") public String json5() throws JsonProcessingException { Date date = new Date(); String json = JsonDateUtils.getJson(date); return json; }
- 这种方式的测试结果和上面的一致
-