SpringMVC入门学习(一)
MVC思想是将一个应用分成3个基本部分, 即Model(模型)、View(视图)和Controller(控制器), 让这3个部分以最低的耦合进行协同工作, 从而提高应用的可扩展性以及可维护性. SpringMVC是一款优秀的基于MVC思想的应用框架, 它是Spring提供的一个实现了web MVC设计模式的轻量级WEB框架.
SpringMVC框架是高度可配置的, 包含多种视图技术, 例如JSP技术、Velocity、Tiles、IText和POI. Spring MVC框架并不关心使用的视图技术, 也不会强迫开发者只使用JSP技术.
SpringMVC框架主要是由DispatcherServlet、处理器映射、控制器、视图解析器、视图组成.
在上图中包含了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对象, 从而将相应结果渲染给客户.
完整代码链接: https://gitee.com/gitsilence/SpringMVC_01
<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>
代码如下:
<!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>
<%--
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>
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");
}
}
在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>
原文链接: 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,.
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"/>
在基于注解的控制类中可以为每个请求编写对应的处理方法. 那么如何将请求与方法一一对应呢 ? 需要使用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类型.