1、回顾Java Servlet和JSP

再学习springmvc之前,先复习一下Servlet和JSP,他们是java web开发的基础和核心,所有的框架都是以他们为基础演化而来,对他们的了解和掌握可以更好的帮助我们去学习java的各种框架。

1.1Java Servlet

Java Servlet 是运行在 Web 服务器或应用服务器上的程序,用于接收处理各种请求和作为数据库或应用程序之间的中间层

使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

下图显示了 Servlet 在 Web 应用程序中的位置。

spring mvc jsp和thymleaf兼容_MVC


1.2JSP

JSP全称Java Server Pages,是一种动态网页开发技术。它使用JSP标签在HTML网页中插入Java代码。标签通常以<%开头以%>结束,用于动态生成网页和相关计算

JSP是一种特殊Java servlet,主要用于实现Java web应用程序的用户界面部分。网页开发者们通过结合HTML代码、XHTML代码、XML元素以及嵌入JSP操作和命令来编写JSP。

JSP通过网页表单获取用户输入数据、访问数据库及其他数据源,然后动态地创建网页。

JSP标签有多种功能,比如访问数据库、记录用户选择信息、访问JavaBeans组件等,还可以在不同的网页中传递控制信息和共享信息。

2、spring mvc的概念
理论上用Servelet和JSP编程做任何工程项目,但是这种方式坐的项目过于松散,不利于项目开发和后期维护,因此才诞生了springmv,springboot,strauts等框架。

2.1、spring mv简介

Spring web mvc框架提供了模型-视图-控制的体系结构和可以用来开发灵活、松散耦合的 web 应用程序的组件。MVC 模式导致了应用程序的不同方面(输入逻辑、业务逻辑和 UI 逻辑)的分离,同时提供了在这些元素之间的松散耦合。

  • 模型封装了应用程序数据,并且通常它们由 POJO 组成。
  • 视图主要用于呈现模型数据,并且通常它生成客户端的浏览器可以解释的 HTML 输出。
  • 控制器主要用于处理用户请求,并且构建合适的模型并将其传递到视图呈现。

DispatcherServlet

Spring Web 模型-视图-控制(MVC)框架是围绕 DispatcherServlet 设计的,DispatcherServlet 用来处理所有的 HTTP 请求和响应。Spring Web MVC DispatcherServlet 的请求处理的工作流程如下图所示:

spring mvc jsp和thymleaf兼容_spring_02

处理流程:

  1. 收到一个 HTTP 请求后,DispatcherServlet 根据 HandlerMapping 来选择并且调用适当的控制器。
  2. 控制器接受请求,并基于使用的 GET 或 POST 方法来调用适当的 service 方法。Service
    方法将设置基于定义的业务逻辑的模型数据,并返回视图名称到 DispatcherServlet 中
  3. DispatcherServlet 会从 ViewResolver 获取帮助,为请求检取定义视图。
  4. 一旦确定视图,DispatcherServlet 将把模型数据传递给视图,最后呈现在浏览器中。

上面所提到的所有组件,即 HandlerMapping(映射处理器)、Controller (控制器)和 ViewResolver(视图解析器) 是 WebApplicationContext 的一部分,而 WebApplicationContext 是带有一些对 web 应用程序必要的额外特性的 ApplicationContext 的扩展。

Spring的模型-视图-控制器(MVC)框架是围绕一个DispatcherServlet(中央处理分发器)来设计的,这个Servlet会把请求分发给各个处理器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传。处理器是你的应用中注解了@Controller和@RequestMapping的类和方法,Spring为处理器方法提供了极其多样灵活的配置。Spring 3.0以后提供了@Controller注解机制、@PathVariable注解以及一些其他的特性,你可以使用它们来进行RESTful web站点和应用的开发。

“对扩展开放”是Spring Web MVC框架一个重要的设计原则,而对于Spring的整个完整框架来说,其设计原则则是“对扩展开放,对修改闭合”。

Spring的视图解析也是设计得异常灵活。控制器一般负责准备一个Map模型、填充数据、返回一个合适的视图名(通过map来传输数据到前端)等,同时它也可以直接将数据写到响应流中。视图名的解析高度灵活,支持多种配置,包括通过文件扩展名、Accept内容头、bean、配置文件等的配置,甚至你还可以自己实现一个视图解析器ViewResolver。模型(MVC中的M,model)其实是一个Map类型的接口,彻底地把数据从视图技术中抽象分离了出来。你可以与基于模板的渲染技术直接整合,如JSP、Velocity和Freemarker等,或者你还可以直接生成XML、JSON、Atom以及其他多种类型的内容。Map模型会简单地被转换成合适的格式,比如JSP的请求属性(attribute),一个Velocity模板的模型等。

spring mvc jsp和thymleaf兼容_spring_03

需求的配置
DispatcherServlet 本质是一个servlet,想让 DispatcherServlet 处理的请求,通过使用在 web.xml 文件中的
一个 URL 映射。下面是一个显示声明和映射 HelloWeb DispatcherServlet 的示例:

web.xml 文件将被保留在你的应用程序的 WebContent/WEB-INF 目录下。在初始化 HelloWeb DispatcherServlet 时,该框架将尝试加载位于该应用程序的 WebContent/WEB-INF 目录中文件名为 [servlet-name]-servlet.xml 的应用程序内容。在示例中,我们的文件将是 HelloWeb-servlet.xml。

接下来, 标签表明哪些 URLs 将被 DispatcherServlet 处理。这里所有以 .jsp 结束的 HTTP 请求将由 HelloWeb DispatcherServlet处理。

如果你不想使用默认文件名 [servlet-name]-servlet.xml 和默认位置 WebContent/WEB-INF,你可以通过在 web.xml 文件中添加 servlet 监听器 ContextLoaderListener 自定义该文件的名称和位置,如下所示:

<web-app...>
....
<context-param>
   <!--配置dispatcher.xml作为mvc的配置文件,可以定义配置文件的位置-->
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/HelloWeb-servlet.xml</param-value>
</context-param>
<listener>
   <listener-class>
      org.springframework.web.context.ContextLoaderListener
   </listener-class>
</listener>
</web-app>

现在,检查 HelloWeb-servlet.xml 文件的请求配置,该文件位于 web 应用程序的 WebContent/WEB-INF 目录下:

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   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-3.0.xsd
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:component-scan base-package="com.tutorialspoint" />

   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     <!--定义视图路径-->
      <property name="prefix" value="/WEB-INF/jsp/" />
       <!--定义视图后缀-->
      <property name="suffix" value=".jsp" />
   </bean>

</beans>

以下是关于 HelloWeb-servlet.xml 文件的一些要点:

[servlet-name]-servlet.xml 文件将用于创建 bean 定义,重新定义在全局范围内具有相同名称的任何已定义的 bean。

标签将用于激活 Spring MVC 注释扫描功能,该功能允许使用注释,如 @Controller 和 @RequestMapping 等等。

InternalResourceViewResolver 将使用定义的规则来解决视图名称。按照上述定义的规则,一个名称为 hello 的逻辑视图将发送给位于 /WEB-INF/jsp/hello.jsp 中实现的视图。

定义控制器

DispatcherServlet 发送请求到控制器中执行特定的功能。@Controller 注释表明一个特定类是一个控制器的作用。***@RequestMapping 注释用于映射 URL 到整个类或一个特定的处理方法***。

@Controller
@RequestMapping("/hello")
public class HelloController{
   @RequestMapping(method = RequestMethod.GET)
   public String printHello(ModelMap model) {
      model.addAttribute("message", "Hello Spring MVC Framework!");
      return "hello";
   }
}

@Controller 注释定义该类作为一个 Spring MVC 控制器。在这里,第一次使用的 @RequestMapping 表明在该控制器中处理的所有方法都是相对于 /hello 路径的。下一个注释 @RequestMapping(method = RequestMethod.GET) 用于声明 printHello() 方法作为控制器的默认 service 方法来处理 HTTP GET 请求。你可以在相同的 URL 中定义其他方法来处理任何 POST 请求。

你可以用另一种形式来编写上面的控制器,你可以在 @RequestMapping 中添加额外的属性,如下所示:

@Controller
public class HelloController{
   @RequestMapping(value = "/hello", method = RequestMethod.GET)
   public String printHello(ModelMap model) {
      model.addAttribute("message", "Hello Spring MVC Framework!");
      return "hello";
   }
}

值属性表明 URL 映射到哪个处理方法,方法属性定义了 service 方法来处理 HTTP GET 请求。关于上面定义的控制器,这里有以下几个要注意的要点:

  • 你将在一个 service 方法中定义需要的业务逻辑。你可以根据每次需求在这个方法中调用其他方法。
  • 基于定义的业务逻辑,你将在这个方法中创建一个模型。你可以设置不同的模型属性,这些属性将被视图访问并显示最终的结果。这个示例创建了一个带有属性
    “message” 的模型。
  • 一个定义的 service 方法可以返回一个包含视图名称的字符串用于呈现该模型。这个示例返回 “hello” 作为逻辑视图的名称。

创建 JSP 视图
对于不同的表示技术,Spring MVC 支持许多类型的视图。这些包括 JSP、HTML、PDF、Excel 工作表、XML、Velocity 模板、XSLT、JSON、Atom 和 RSS 提要、JasperReports 等等。但我们最常使用利用 JSTL 编写的 JSP 模板。所以让我们在 /WEB-INF/hello/hello.jsp 中编写一个简单的 hello 视图:

<html>
   <head>
   <title>Hello Spring MVC</title>
   </head>
   <body>
   <h2>${message}</h2>
   </body>
</html>

其中,${message} 是我们在控制器内部设置的属性。你可以在你的视图中有多个属性显示。

Spring MVC Hello World 例子
下面的例子说明了如何使用 Spring MVC 框架来编写一个简单的基于 web 的 Hello World 应用程序。

这里是 HelloController.java 文件的内容:

package com.tutorialspoint;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.ui.ModelMap;
@Controller
@RequestMapping("/hello")
public class HelloController{ 
   @RequestMapping(method = RequestMethod.GET)
   public String printHello(ModelMap model) {
      model.addAttribute("message", "Hello Spring MVC Framework!");
      return "hello";
   }
}

ModelMap model是一个高级的map,用来传递模型数据

下面是 Spring Web 配置文件 web.xml 的内容

<web-app id="WebApp_ID" version="2.4"
   xmlns="http://java.sun.com/xml/ns/j2ee" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

   <display-name>Spring MVC Application</display-name>

   <servlet>
      <servlet-name>HelloWeb</servlet-name>
      <servlet-class>
         org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>

   <servlet-mapping>
      <servlet-name>HelloWeb</servlet-name>
      <url-pattern>/</url-pattern>
   </servlet-mapping>

</web-app>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:context="http://www.springframework.org/schema/context"
   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-3.0.xsd
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:component-scan base-package="com.tutorialspoint" />

   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/WEB-INF/jsp/" />
      <property name="suffix" value=".jsp" />
   </bean>

</beans>

下面是 Spring 视图文件 hello.jsp 的内容:

spring mvc jsp和thymleaf兼容_spring_04


Spring MVC 表单处理例子


https://www.w3cschool.cn/wkspring/v41f1mmk.html

Spring 页面重定向例子
下面的例子说明了如何编写一个简单的基于 web 的应用程序,它利用重定向来传送一个 http 请求到另一个页面中。

package com.tutorialspoint;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class WebController {
   @RequestMapping(value = "/index", method = RequestMethod.GET)
   public String index() {
       return "index";
   }   
   @RequestMapping(value = "/redirect", method = RequestMethod.GET)
   public String redirect() {     
      return "redirect:finalPage";//定义重定向
   }   
   @RequestMapping(value = "/finalPage", method = RequestMethod.GET)
   public String finalPage() {     
      return "final";
   }
}

Spring 静态页面例子

package com.tutorialspoint;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class WebController {
   @RequestMapping(value = "/index", method = RequestMethod.GET)
   public String index() {
       return "index";//调取index.jsp,定义一个视图
   }   
   @RequestMapping(value = "/staticPage", method = RequestMethod.GET)
   public String redirect() {     
      return "redirect:/pages/final.htm";//定义静态页面,重定向到final.html
   }
}

Spring 异常处理例子
什么是异常:
程序未按预期执行时,就会抛出异常终止程序,以保证程序按预期执行。
为什么要捕获异常:
因为应用程序是非常复杂的,不可能对所有的错误都进行定义,不可能考虑到所有的异常,因此通过捕获异常的机制来控制程序的正常执行,出现了异常就抛出异常,终止程序,定位错误。

1、定义异常

下面是 SpringException.java 文件的内容:

package com.tutorialspoint;
public class SpringException extends RuntimeException{
   private String exceptionMsg;   
   public SpringException(String exceptionMsg) {
      this.exceptionMsg = exceptionMsg;
   }   
   public String getExceptionMsg(){
      return this.exceptionMsg;
   }   
   public void setExceptionMsg(String exceptionMsg) {
      this.exceptionMsg = exceptionMsg;
   }
}

下面是 StudentController.java 文件的内容。这里,你需要使用 @ExceptionHandler 注解一个 service 方法,你可以指定要处理的一个或多个异常。如果你要指定一个以上的异常,那么你可以使用逗号分隔这些值。

package com.tutorialspoint;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.ui.ModelMap;
@Controller
public class StudentController {
   @RequestMapping(value = "/student", method = RequestMethod.GET)
   public ModelAndView student() {
      return new ModelAndView("student", "command", new Student());
   }
   @RequestMapping(value = "/addStudent", method = RequestMethod.POST)
   @ExceptionHandler({SpringException.class})
   public String addStudent( @ModelAttribute("HelloWeb")Student student, 
      ModelMap model) {
      if(student.getName().length() < 5 ){
         throw new SpringException("Given name is too short");
      }else{
       model.addAttribute("name", student.getName());
      }     
      if( student.getAge() < 10 ){
         throw new SpringException("Given age is too low");
      }else{
       model.addAttribute("age", student.getAge());
      }
      model.addAttribute("id", student.getId());
      return "result";
   }
}

下面是另一个 Spring Web 配置文件 HelloWeb-servlet.xml 的内容:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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-3.0.xsd
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:component-scan base-package="com.tutorialspoint" />

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
   <property name="prefix" value="/WEB-INF/jsp/" />
   <property name="suffix" value=".jsp" />
</bean>
<!--定义异常视图-->
<bean class="org.springframework.web.servlet.handler.
      SimpleMappingExceptionResolver">
   <property name="exceptionMappings">
      <props>
         <prop key="com.tutorialspoint.SpringException">
            ExceptionPage    
         </prop>
      </props>
   </property>
   <property name="defaultErrorView" value="error"/>
</bean>

</beans>

下面是 Spring 视图文件 ExceptionPage.jsp 的内容。在这里,你将通过 ${exception} 访问异常实例。

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
    <title>Spring MVC Exception Handling</title>
</head>
<body>

<h2>Spring MVC Exception Handling</h2>

<h3>${exception.exceptionMsg}</h3>

</body>
</html>

如果引用程序出现了异常就会跳转到异常视图:

spring mvc jsp和thymleaf兼容_xml_05

使用@RequestParam将请求参数绑定至方法参数
你可以使用@RequestParam注解将请求参数绑定到你控制器的方法参数上。

下面这段代码展示了它的用法:

@Controller
@RequestMapping("/pets")
@SessionAttributes("pet")
public class EditPetForm {
    // ...
    @RequestMapping(method = RequestMapping.GET)
    public String setupForm(@RequestParam("petId") int petId, ModelMap model) {
        Pet pet = this.clinic.loadPet(petId);
        model.addAttribute("pet", pet);
        return "petForm";
    }
    
    //@RequestParam("petId")可以省略掉,直接将请求参数与控制器方法参数进行绑定
    public String setupForm( int petId, ModelMap model) {
        Pet pet = this.clinic.loadPet(petId);
        model.addAttribute("pet", pet);
        return "petForm";
    }

    // ,..
}

使用@ResponseBody注解映射响应体

@ResponseBody注解与@RequestBody注解类似。@ResponseBody注解可被应用于方法上,标志该方法的返回值,应该被直接写回到HTTP响应体中去(而不会被被放置到Model中或被解释为一个视图名)。举个例子:

@RequestMapping(path = “/something”, method = RequestMethod.PUT)
 @ResponseBody
 public String helloWorld() {
 return “Hello World”;
 }

上面面的代码结果是文本Hello World将被写入HTTP的响应流中,浏览器页面最后会出现“Hello World"” 字符串。。

使用@RestController注解创建REST控制器

当今让控制器实现一个REST API是非常常见的,这种场景下控制器只需要提供JSON、XML或其他自定义的媒体类型内容即可。你不需要在每个@RequestMapping方法上都增加一个@ResponseBody注解,更简明的做法是,给你的控制器加上一个@RestController的注解。

@RestController是一个原生内置的注解,它结合了@ResponseBody与@Controller注解的功能。不仅如此,它也让你的控制器更表义,而且在框架未来的发布版本中,它也可能承载更多的意义。

与普通的@Controller无异,@RestController也可以与@ControllerAdvicebean配合使用。更多细节,请见使用@ControllerAdvice辅助控制器

URI模板
URI模板可以为快速访问@RequestMapping中指定的URL的一个特定的部分提供很大的便利。
在Spring MVC中你可以在方法参数上使用**@PathVariable注解,将其与URI模板中的参数绑定起来**:

@RequestMapping(path="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable String ownerId, Model model) {
    Owner owner = ownerService.findOwner(ownerId);
    model.addAttribute("owner", owner);
    return "displayOwner";
}

Spring MVC还有其他特性,先了解基础使用方法和特性,其他方法可在实际开发中学习。可参考一下链接学习:

https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/spring_mvc_documentation_linesh_translation-bea827s6.html