springmvc入门
1.springmvc简介
1.1 mvc:model view controller (重要概念)
是一种软件架构思想、软件设计规范,将软件按照模型、视图、控制器来划分。它将业务逻辑、数据、显示分离,降低耦合。
-
模型层:
model模型是指模型表示业务规则。模型代表一个存取数据的对象或 JAVA 实体类,它也可以带有逻辑,在数据变化时更新控制器。即可以理解为数据+行为。
dao、service、pojo
-
视图层:
View视图是指用户看到并与之交互的界面。比如由html元素组成的网页界面,或者软件的客户端界面jsp。
jsp、html
-
控制器:
controller控制器是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。
servlet
*注:三层架构 VS mvc模型。*这两个不是一个东西
*三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,*表述层表示前台页面和后台servlet
三层架构的分层模式是典型的上下关系,上层依赖于下层。但MVC作为表现模式是不存在上下关系的,而是相互协作关系。
1.2 Springmvc
springmvc = spring+mvc
- 我们为什么要学习SpringMVC呢?
Spring MVC的特点:
- 基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理
- 与Spring兼容性好,无缝结合(使用SpringIoC可以很容易把所有bean都注册好,使用起来简单;AOP可以简单搞起拦截器等等)
- 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
- 功能强大:RESTful、数据验证、格式化、本地化、主题等
- 性能强大,企业用的人多
2.springmvc初体验-HelloWorld
2.2 正式开始 maven+springmvc
- 使用idea初始化一个maven如图项目,使用maven+webapp支持:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-czZeUo5x-1688372413887)(springmvc入门 -S.assets/image-20211109172558556.png)]
注意:第一次使用maven会自动加载需要的插件和包,我们在这个过程中不要做操作,观察进度条等待maven完成初始化,中间不能中断,中断创建结构会失败。创建成功后,pom会如图自动配置插件,自动生成空白web.xml。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zrtE5xFe-1688372413888)(springmvc入门.assets/image-20211120170422622.png)]
-
根据maven的标准项目结构,在main文件夹下添加src、resources文件夹和对应支持。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B3lOAojA-1688372413888)(springmvc入门.assets/image-20211120170101640.png)]
-
导入包
<!-- SpringMVC这个版本的包里会导入spring的包 maven导入后检查是否存在依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
至此,我们就初步完成了springmvc+maven的初始化项目结构。
2.2 配置 web.xml + 详细讲解
<?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_3_1.xsd"
version="3.1">
<!--注册DispatcherServlet-->
<servlet>
<servlet-name>springmvcServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvcServlet-servlet.xml</param-value>
</init-param>
<!--load-on-startup 的值大于0就表示随着服务器启动,让这个Servlet随Servlet容器一起启动。-->
<!--
作为框架的核心组件,在启动过程中有大量的初始化操作要做
而这些操作放在第一次请求时才执行会严重影响访问速度
因此需要通过此标签将启动控制DispatcherServlet的初始化时间提前到服务器启动时
-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--servlet匹配路径,转向目标controller-->
<!--拦截匹配的请求,Servlet拦截匹配规则要自已定义-->
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<servlet-mapping>
<servlet-name>springmvcServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.3 写一个controller+jsp
controller
package com.liyw.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 MyController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
//业务处理....
mv.addObject("msg","Hello SpringMVC!");
mv.setViewName("hello");
return mv;//最终转向/WEB-INF/jsp/hello.jsp
}
}
/WEB-INF/jsp/hello.jsp
<%--
Created by IntelliJ IDEA.
User: win
Date: 2021/11/10
Time: 9:49
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>hello界面</title>
</head>
<body>
${msg}
</body>
</html>
2.4 springmvc的配置文件springmvcServlet-servlet.xml
根据springmvc的官方规范,SpringMVC 的配置文件,文件名为 [servletname]-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<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"
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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--这两个不是必须的 正式代码不配置 但是可以帮助大家理解运行顺序 这里开始-->
<!--处理映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--这两个不是必须的 正式代码不配置 但是可以帮助大家理解运行顺序 这里结束-->
<bean id="/hello" class="com.liyw.controller.MyController"></bean>
<!--视图解析器: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>
</beans>
注意:这里的class写的是我们controller代码的全类名,id写的值会拼接到我们项目的路径后面,组成我们的url。
即访问 http://localhost:8080/项目名/hello
<bean id="/hello" class="com.liyw.controller.MyController"></bean>
最终项目结构如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5UXMXiYQ-1688372413889)(springmvc入门 -S.assets/image-20220722105859967.png)]
2.6 配置tomcat进行测试
请特别注意tomcat版本与web-app的版本关系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tTHufB33-1688372413889)(springmvc入门 -S.assets/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=.png)]
结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ji3hznxx-1688372413890)(springmvc入门.assets/image-20211110111430451.png)]
3.Springmvc运行原理(最重要的概念)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LilWtnjM-1688372413890)(springmvc入门 -S.assets/70.png)]
流程说明:
(1)客户端(浏览器)发送请求,容器去web.xml找符合前端控制器的url-pattern,符合条件会请求到DispatcherServlet。
(2)DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。–去匹配对应的bean
(3)解析到对应的Handler后,开始由HandlerAdapter适配器处理。
(4)HandlerAdapter会根据Handler来调用真正的处理器来处理请求,并处理相应的业务逻辑
—也就是让对应的controller里对应方法做该做的事儿。
(5)处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是个逻辑上的View。
(6)ViewResolver会根据配置去加上前缀和后缀组成视图的路径,并且查找到实际的View。
(7)DispaterServlet把返回的Model传给View。
(8)通过View响应给请求者(浏览器)
ref:https://www.cnblogs.com/xiaoxi/p/6164383.html
springmvc帮我们封装了图示中大部分功能,我们需要实现的主要就是对应controller+对应界面+相关业务逻辑,工作量大大减少。
这里建议大家将这张原理图和我们的代码配置比对这看,思考这中间的逻辑关系,这一部分概念是springmvc面试的重要考点,希望大家能理解并记忆。
4.注解方式
我们之前的demo用最简单的例子来讲解了springmvc以及它的工作机制,但是在我们真实的项目工程中,我们往往采用注解的形式来coding。
和spring的注解一样,能大大减少我们的项目配置。
4.1 springmvc-servlet.xml
添加约束mvc 和 context的约束
<?xml version="1.0" encoding="UTF-8"?>
<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"
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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--开启扫描包(代替我们自己的controller层bean注册)-->
<context:component-scan base-package="com.liyw"/>
<!--开启SpringMVC的注解驱动-->
<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>
4.2 @controller的写法
package com.liyw.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloWorldController {
@RequestMapping("/hello")
public String getFirstPage(Model model){
System.out.println("进入hello方法");
model.addAttribute("msg","Hello SpringMVC!");
return "hello";
}
}
测试时 也会展示 /WEB-INF/jsp/hello.jsp 效果是一样的
5. 注解 @RequestMapping
5.1、功能
从注解名称上我们可以看到,@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。
SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。
5.2、位置
@RequestMapping标识一个类:设置映射请求的请求路径的初始信息
@RequestMapping标识一个方法:设置映射请求请求路径的具体信息
@Controller
@RequestMapping("/controller")
public class HelloWorldController{
//此时的路径 为 http://localhost:8081/controller/login
@RequestMapping("/login")
public String login(){
System.out.println("=====进入login");
return "hello";
}
}
5.3.@RequestMapping注解的method属性通过请求的请求方式(get或post)匹配请求映射
注:
1、对于处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解
处理get请求的映射–>@GetMapping
处理post请求的映射–>@PostMapping
处理put请求的映射–>@PutMapping
处理delete请求的映射–>@DeleteMapping
举例:相同的两个方法,换了@postmapping之后就无法访问了,因为默认是get方式:
Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method ‘GET’ not supported]
6、SpringMVC获取请求参数
都用get方式请求
6.1、通过ServletAPI获取
将HttpServletRequest作为控制器方法的形参,此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象
@RequestMapping("/getUser1")
public String testParam(HttpServletRequest request){
String username = request.getParameter("userName");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "success";
}
6.2、通过控制器方法的形参获取请求参数
在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参
@RequestMapping("/getUser2")
public String getUser2(String userName,String password){
System.out.println("username:"+userName+",password:"+password);
return "success";
}
注:
若请求所传输的请求参数中有多个同名的请求参数,此时可以在控制器方法的形参中设置字符串数组或者字符串类型的形参接收此请求参数
若使用字符串数组类型的形参,此参数的数组中包含了每一个数据
若使用字符串类型的形参,此参数的值为每个数据中间使用逗号拼接的结果
6.3、@RequestParam
@RequestParam是将请求参数和控制器方法的形参创建映射关系
@RequestParam注解一共有三个属性:
-
value:指定为形参赋值的请求参数的参数名
-
required:设置是否必须传输此请求参数,默认值为true
若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400:Required String parameter ‘xxx’ is not present;若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null
- defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为""时,则使用默认值为形参赋值
@RequestMapping("/getUser3")
public String getUser3(@RequestParam("userName") String name, @RequestParam("password")String pass){
System.out.println("username:"+name+",password:"+pass);
return "success";
}
6.4、@RequestHeader
@RequestHeader是将请求头信息和控制器方法的形参创建映射关系
@RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
6.5、@CookieValue
@CookieValue是将cookie数据和控制器方法的形参创建映射关系
@CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
6.6、通过POJO获取请求参数
当参数过多时,上述参数的一一对应的方式就会显得代码中很乱,解决这一问题就需要使用POJO进行多参数封装。Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值(通过属性的set方法)。
可以在控制器方法的形参位置设置一个实体类类型的形参,此时若浏览器传输的请求参数的参数名和实体类中的属性名一致,那么请求参数就会为此属性赋值
@RequestMapping("/getUser4")
public String getUser4(User user){
System.out.println("username:"+user.getUserName()+",password:"+user.getPassword());
return "success";
}
代码汇总:
package com.liyw.controller;
import com.liyw.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
@RequestMapping("/user")
@Controller
public class UserController {
//http://localhost:8081/user/getUser1?userName=Amy&password=1111
@RequestMapping("/getUser1")
public String testParam(HttpServletRequest request){
String username = request.getParameter("userName");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "success";
}
@RequestMapping("/getUser2")
public String getUser2(String userName,String password){
System.out.println("username:"+userName+",password:"+password);
return "success";
}
@RequestMapping("/getUser3")
public String getUser3(@RequestParam("userName") String name, @RequestParam("password")String pass){
System.out.println("username:"+name+",password:"+pass);
return "success";
}
@RequestMapping("/getUser4")
public String getUser4(User user){
System.out.println("username:"+user.getUserName()+",password:"+user.getPassword());
return "success";
}
}
jsp
<%--
Created by IntelliJ IDEA.
User: win
Date: 2021/11/10
Time: 14:27
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户数据提交</title>
</head>
<body>
<form action="../user/getUser1" method="post">
<p>用户名</p><input type="text" name="userName">
<p>密码</p><input type="text" name="password">
<input type="submit">
</form>
</body>
</html>
@RequestMapping("/user")
@Controller
public class UserController {
@RequestMapping("/userPage")
public String userPage(){
return "user";
}
//http://localhost:8081/user/getUser1?userName=Amy&password=1111
@RequestMapping("/getUser1")
public String testParam(HttpServletRequest request){
String username = request.getParameter("userName");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "success";
}
}
6.7、解决获取请求参数的乱码问题
解决获取请求参数的乱码问题,可以使用SpringMVC提供的编码过滤器CharacterEncodingFilter,但是必须在web.xml中进行注册,并且配置在servlet配置之前。
过滤器
<!--filter配置要放在Servlet之前-->
<!--配置过滤器:解决中文乱码问题-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<!--这里的param-name固定是encoding不能变-->
<param-name>encoding</param-name>
<param-value>utf8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注:
SpringMVC中处理编码的过滤器一定要配置到其他过滤器之前,否则无效
.7、解决获取请求参数的乱码问题
解决获取请求参数的乱码问题,可以使用SpringMVC提供的编码过滤器CharacterEncodingFilter,但是必须在web.xml中进行注册,并且配置在servlet配置之前。
过滤器
<!--filter配置要放在Servlet之前-->
<!--配置过滤器:解决中文乱码问题-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<!--这里的param-name固定是encoding不能变-->
<param-name>encoding</param-name>
<param-value>utf8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注:
SpringMVC中处理编码的过滤器一定要配置到其他过滤器之前,否则无效