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把一个项目分成三部分,包括视图、控制、模型。

图片

  1. 用户发请求
  2. Servlet接收请求数据,并调用对应的业务逻辑方法
  3. 业务处理完毕,返回更新后的数据给servlet
  4. servlet转向到JSP,由JSP来渲染页面
  5. 响应给前端更新后的页面
  • 职责分析:

    • Controller:控制器

      1. 取得表单数据
      2. 调用业务逻辑
      3. 将业务保存测数据,发送、转向指定的页面

      Model:模型

      1. 业务逻辑
      2. 保存数据的状态

      View:视图

      1. 显示页面,展示模型层中保存的数据
  • 优缺点分析

    • 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项目

    • 然后点击如下

      创建一个子Maven-web项目 创建一个子Maven-web项目2

      创建一个子Maven-web项目3

  • 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的概述

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,排查步骤:

      1. 查看控制台输出,看一下是不是缺少了什么jar包。
      2. 如果jar包存在,显示无法输出,就在IDEA的项目发布中,添加lib依赖!
      3. 重启Tomcat 即可解决!

      出现404

    hellospringmvc

5.springmvc执行原理

5.1 springmvc简单原理

  • Spring MVC 下我们一般把后端项目分为 Service层(处理业务)、Dao层(数据库操作)、Entity层(实体类)、Controller层(控制层,返回数据给前台页面)。

Spring MVC 简单的工作原理图如下:

img

5.2 springmvc 底层工作原理

图片

图为SpringMVC的一个较完整的流程图,实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现。

简要分析执行流程

  1. DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。

    我们假设请求的url为 : http://localhost:8080/SpringMVC/hello

    如上url拆分成三部分:

    http://localhost:8080服务器域名

    SpringMVC部署在服务器上的web站点

    hello表示处理器

    通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello处理器。

  2. HandlerMapping为处理器映射(接口)。由DispatcherServlet自己调用HandlerMapping,HandlerMapping根据请求url解析查找对应的Handler处理器。

  3. (((((

    HandlerExecution表示具体的Handler处理器,如上url被查找处理器为:hello。

  4. HandlerExecution将解析后的信息(如:生成处理器对象及处理器拦截器,解析控制器映射等)传递给DispatcherServlet。

    )))))

  5. DispatcherServlet调用HandlerAdapter处理器适配器(接口),其作用是:按照特定的规则去执行Handler,找到具体的Controller去执行该处理器

  6. Handler让具体的Controller执行,并处理相应的业务。通过HandlerAdapter对处理器进行执行, 经过适配调用得到具体的处理器(Controller,也叫后端控制器)。

  7. Controller将具体的执行信息(如:ModelAndView对象,需要返回给前端的数据,跳转的页面等)返回给HandlerAdapter。(后面controller还可以调用业务层)

  8. HandlerAdapter又将ModelAndView 对象(包含模型数据、逻辑视图名)传递给DispatcherServlet。

  9. DispatcherServlet获取了ModelAndView,调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。(解析ModelAndView的视图名字,解析的方式可以有拼接视图名等

    • Model 是返回的数据对象,View 是个逻辑上的 View
    • ViewResolver 会根据逻辑 View 查找实际的 View
    • DispaterServlet 把返回的 Model 传给 View(视图渲染)。
    • View 返回给请求者(浏览器)
  10. 视图解析器将解析后的逻辑视图名传给DispatcherServlet。

  11. DispatcherServlet根据视图解析器解析的视图结果,将数据渲染到视图上,调用具体的视图。

  12. 最终视图呈现给用户。

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

四.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操作资源的区别

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";
    }    
}

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";
          }
      }
      
  • 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)

    • 浏览器输入:http://localhost:8080/springmvcController/result/t1

    • 浏览器输入:http://localhost:8080/springmvcController/result/t2

    • 浏览器输入:http://localhost:8080/springmvcController/result/t3

    • 注意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)使用视图解析器

七.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)

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

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;
      }
      
      • 这种方式的测试结果和上面的一致

十.springmvc的Ajax技术

posted @ 2021-05-07 05:46  维他命D片  阅读(68)  评论(0编辑  收藏  举报