目录
SpringMVC入门学习(一)
/  

SpringMVC入门学习(一)

SpringMVC入门学习(一)

   MVC思想是将一个应用分成3个基本部分, 即Model(模型)、View(视图)和Controller(控制器), 让这3个部分以最低的耦合进行协同工作, 从而提高应用的可扩展性以及可维护性. SpringMVC是一款优秀的基于MVC思想的应用框架, 它是Spring提供的一个实现了web MVC设计模式的轻量级WEB框架.

MVC模式

  • 模型: 用于存储数据库以及处理用户请求的业务逻辑
  • 视图: 向控制器提交数据, 显示模型中的数据
  • 控制器: 根据视图提出的请求判断将请求和数据交给哪个模型处理, 将处理后的有关结果及交给哪个视图更新显示

Spring MVC工作原理

   SpringMVC框架是高度可配置的, 包含多种视图技术, 例如JSP技术、Velocity、Tiles、IText和POI. Spring MVC框架并不关心使用的视图技术, 也不会强迫开发者只使用JSP技术.

   SpringMVC框架主要是由DispatcherServlet、处理器映射、控制器、视图解析器、视图组成.

  1. 客户端请求提交到DispatcherServlet
  2. 由DispatcherServlet控制器寻求一个或多个HandlerMapping, 找到处理请求的Controller
  3. DispatcherServlet将请求提交到Controller
  4. Controller调用业务逻辑处理后返回ModelAndView
  5. DispatcherServlet寻求一个或多个ViewResolver视图解析器, 找到ModelAndView指定的视图
  6. 视图负责将结果显示到客户端

SpringMVC接口

   在上图中包含了4个SpringMVC接口, 即DispatcherServlet、HandlerMapping、Controller和ViewResolver.

   SpringMVC所有请求都经过DispatcherServlet来统一分发, 在DispatcherServlet将请求分发给Controller之前需要借助SpringMVC提供的HandlerMapping定位到具体的Controller.

   HandlerMapping接口负责完成客户请求到Controller映射.

   Controller接口将处理用户的请求, 这和Java Servlet扮演的角色是一致的, 一旦Controller处理完用户请求, 将返回的ModelAndView对象给DispatcherServlet前端控制器, ModelAndView中包含模型和视图. 从宏观角度考虑, DispatcherServlet是整个web应用的控制器, 从微观上考虑, Controller是单个http请求处理过程中的控制器, 而ModelAndView是http请求过程中返回的模型和视图.

   ViewResolver接口(视图解析器)在web应用中负责查找view对象, 从而将相应结果渲染给客户.

第一个Spring MVC应用

完整代码链接: https://gitee.com/gitsilence/SpringMVC_01

导入相关jar包

  • 导入spring基本jar包
  • spring-web-xxx.jar
  • spring-webmvc-xxx.jar

pom.xml

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <!--      <scope>test</scope>-->
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.5.RELEASE</version>
    </dependency>

    <!--    第三方jar-->
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>
      
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-servlet-api</artifactId>
      <version>9.0.12</version>
    </dependency>
  </dependencies>

在web.xml文件中部署DispatcherServlet

代码如下:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>


<!--  部署DispatcherServlet-->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--    表示容器在启动时立即加载-->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
<!--    处理所有的URL-->
    <url-pattern>/</url-pattern>
  </servlet-mapping>

   上述DispatcherServlet的servlet对象springmvc初始化时将在应用程序的WEB-INF目录下查找一个配置文件, 该配置文件的命名规则是 'servletName-servlet.xml', 例如: springmvc-servlet.xml

   另外, 也可以将SpringMVC配置文件存放在应用程序目录中的任何地方, 但需要使用servlet的init-param元素加载配置文件, 示例代码如下:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>


<!--  部署DispatcherServlet-->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring-config/springmvc-servlet.xml</param-value>
    </init-param>
    
    
<!--    表示容器在启动时立即加载-->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
<!--    处理所有的URL-->
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

创建web应用首页 index.jsp

<%--
  Created by 年少、.
  User: nianshao
  Date: 19-11-3
  Time: 下午2:38
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta charset="UTF-8">
<head>
    <title>Title</title>
</head>
<body>

    未注册的用户, 请 <a href="${pageContext.request.contextPath}/register">主页</a><br>
    已注册的用户, 去 <a href="${pageContext.request.contextPath}/login">登录</a>

</body>
</html>

创建Controller类

  • LoginController

    package cn.lacknb.controller;
    
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class LoginController implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
            return new ModelAndView("/WEB-INF/jsp/login.jsp");
        }
    }
    
    
  • RegisterController

    package cn.lacknb.controller;
    
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    
    public class RegisterController implements Controller {
        @Override
        public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
            return new ModelAndView("/WEB-INF/jsp/register.jsp");
        }
    }
    
    

创建SpringMVC配置文件并配置Controller映射信息

   在WEB-INF目录下创建名为: spring-config/springmvc-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    LoginController控制类, 映射到 /login-->
    <bean id="/login" class="cn.lacknb.controller.LoginController"/>

<!--    RegisterController控制器类, 映射到 /registe-->
    <bean id="/register" class="cn.lacknb.controller.RegisterController"/>
</beans>

IDEA下${pageContext.request.contextPath}不生效问题

原文链接: https://blog.csdn.net/l577217/article/details/81490910

在idea下,已经添加了jsp的jar包,其中一个.jsp文件中表单提交为:

action="${pageContext.request.contextPath}/login"

部署到tomcat上,在浏览器访问后显示错误:

但是同样的文件在eclipse下可以正常访问,通过给出的url可以看出是EL表达式解析错误

解决方法1:为在.jsp文件前面设置属性:

<%@page isELIgnored="false"%>

解决方法2:更改web.xml命名空间:

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">

</web-app>

视图解析器

   用户可以在配置文件中定义SpringMVC的一个视图解析器(ViewResolver), 代码如下:

    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp" />
    </bean>

   上述视图解析器配置了前缀和后缀两个属性, RegisterController和LoginController控制器类的视图路径仅需提供register和login, 视图解析器将会自动添加前缀和后缀.

例如: 现在将RegisterController修改如下 :

package cn.lacknb.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class RegisterController implements Controller {
    @Override
    public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
        return new ModelAndView("register");
    }
}

重新运行, 点击注册, 运行成功.

注意: 当设置前缀和后缀之后, LoginController也要对应做出修改.

基于注解的控制器

   使用基于注解的控制器有以下两个优点:

   (1) 在基于注解的控制器类中可以编写多个处理方法, 进而可以处理多个请求(动作), 这就允许将相关的操作编写在同一个控制器类中, 从而减少控制器类的数量, 方便以后的维护.

   (2) 基于注解的控制器不需要在配置文件中部署映射, 仅需要使用RequestMapping注释类型注解一个方法进行请求处理.

   在SpringMVC中最重要的的两个注解类型是Controller和RequestMapping,.

Controller注解类型

package controller

import org.springframework.stereotype.Controller

/*
* @Controller 表示IndexController的实例是一个控制器
*/
@Controller
public class IndexController{
}

   在Spring MVC中使用扫描机制找到应用中所有基于注解的控制类, 所以, 为了让控制器被Spring MVC框架扫描到, 需要在配置文件中声明 spring-Context, 并使用< context:component-scan/ >元素指定控制类的基本包

<context:component-scan base-package="cn.lacknb.controller"/>

RequestMapping注解类型

   在基于注解的控制类中可以为每个请求编写对应的处理方法. 那么如何将请求与方法一一对应呢 ? 需要使用org.springframework.web.bind.annotation.RequestMapping 注解类型将请求与处理方法一一对应.

  • 方法级别注解的示例代码

    package cn.lacknb.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class IndexController {
    
        @RequestMapping(value = "login")
        public String login(){
            /*
            * login代表逻辑视图, 需要根据SpringMVC配置
            * 文件中internalResourceViewResolver的前缀和后缀找到对应的物理视图
            * */
            return "login";
        }
    
        @RequestMapping(value = "register")
        public String register(){
            return "register";
        }
    
    }
    
    
  • 类级别的注解

    package cn.lacknb.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    @RequestMapping("/")
    public class IndexController {
    
        @RequestMapping("login")
        public String login(){
            /*
            * login代表逻辑视图, 需要根据SpringMVC配置
            * 文件中internalResourceViewResolver的前缀和后缀找到对应的物理视图
            * */
            return "login";
        }
    
        @RequestMapping("register")
        public String register(){
            return "register";
        }
    
    }
    
    

       在类级别注解的情况下, 控制器类中的所有方法都将映射为类级别的请求.

   为了方便维护程序, 建议开发者采用类级别注解, 将相关处理放在同一个控制类中. 例如, 对商品的增、删、改、查处理方法都可以放在同一控制类中.

编写请求处理方法

   在控制类中每个请求处理方法可以有多个不同类型的参数, 以及一个多种类型的返回结果.

如果需要在请求处理方法中使用servlet API类型, 那么可以将这些类型作为请求处理方法的参数类型 .

package cn.lacknb.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Controller
@RequestMapping("/")
public class SpringServlet {
    
    @RequestMapping("login")
    public String login(HttpSession session, HttpServletRequest request){
        session.setAttribute("skey", "session范围的值");
        request.setAttribute("rkey", "request范围的值");
        return "login";
    }
    
} 

   除了Servlet API参数类型外, 还有输入输出流、表单实体类、注解类型、与Spring框架相关的类型等. 其中特别重要的是org.springframework.ui.Model类型, 该类型是一个包含Map的Spring框架类型. 在每次调用请求处理方法时 SpringMVC都将创建org.springframework.ui.Model对象

package cn.lacknb.controller;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/")
public class IndexModel {
    
    @RequestMapping("/register")
    public String register(Model model){
        /*
        * 在视图中可以使用EL表达式${success}取出model值
        * 
        * */
        
        model.addAttribute("success", "注册成功");
        return "register";
    }
    
}

   最常见的返回类型就是代表逻辑视图名称的String类型, 除了String类型以外, 还有ModelAndView、Model、View以及其他任意的java类型.


标题:SpringMVC入门学习(一)
作者:gitsilence
地址:https://blog.lacknb.cn/articles/2019/11/04/1577974160793.html