1.SpringMVC快速入门
- MVC是一种软件架构模式,分离了哑无逻辑和显示界面,包括model 模型、view视图、controller控制器,其中model负责处理业务逻辑,封装试题,view视图展现内容,controller控制器负责调度分发,如接受请求,调用模型,发出响应
![]()
- SpingMVC是一种基于java的实现MVC 设计模式的轻量级web框架,属于SpringFrameWork的后续产品,融合在Spring Web Flow中,通过一套注解让一个简单的java成为处理请求的控控制器,无须实现任何借口,同时还支持RESTful编程风格的请求
- 封装了原来的servlet中的共有行为,实现了参数封装,视图转发等功能
![]()
- 快速入门
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>springmvc_quick</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!--springMVC坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
<!--servlet坐标-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--jsp坐标-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
- 配置SpringMVC前端控制器 DispathcerServlet
<?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>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring_mvc.xml</param-value>
</init-param>
<!-- 启动时加载-->
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 编写Controller类和视图页面,使用注解配置Controller类中业务方法的映射地址
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>成功响应</title>
</head>
<body>
<%--视图页面--%>
<h2>成功响应springmvc</h2>
</body>
</html>
package com.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserController {
// 编写Controller类,跳转到/quick地址并响应
@RequestMapping("/quick")
public String quick(){
System.out.println("收到请求了");
return "success.jsp";
}
}
- 配置SpringMVC核心文件 spring-mvc.xml
<!-- 开启注解扫描-->
<context:component-scan base-package="controller"/>
- 执行流程:Tomcat接受客户端发出的请求,解析请求资源地址,创建代表请求对象和响应对象,调用目标资源,此时通过前置DispatchServlet进行地址解析,将请求发送给对应的/quick的controller,执行响应,将响应传给前置DispatchServlet解析,组装成对应的响应发送给客户端
![]()
2.springmvc执行流程
- 执行组件(springMVC三大组件是处理器映射器,处理器适配器,和视图解析器;四大组件是前端控制器,视图解析器,处理器适配器和处理器映射器)
- 前端控制器DispatcherServlet:用户请求到达前端控制器,由它调用其他组件处理用户的请求,降低了组件之间的耦合性
- 处理器映射器HandlerMapping:通过映射器对处理器进行适配,对更多类型的处理器进行执行,采用了适配器模式
- 处理器Handler:由开发者编写,是真正执行请求的控制器,对具体业务进行处理
- 视图解析器ViewResolver:负责将处理结果生成view视图,它首先将逻辑视图名解析层物理视图名,找到对应的页面地址,再生成view视图对象,对view进行渲染并将结果通过页面展示给用户
- 视图view:有开发者编写,springMVC支持很多的view视图类型,如jstlView、freemarkerView、pdfView等,最常用的是jsp,通过页面标签或页面模板技术将页面展示给用户
- 自定义配置三大组件
<!-- 配置处理器适配器和处理器映射器 ,可以对json格式解析,进行了方法的增强-->
<mvc:annotation-driven/>
- 执行流程
- 用户发送请求到前端控制器DispatcherServlet,前端控制器收到请求后调用处理器映射器HandlerMapping
- 处理器映射器根据请求,通过xml配置或注解方式找到对应的处理器,生成处理器对象和处理器拦截器,并返回给前端控制器
- 前端控制器调用处理器适配器HandlerAdapter,由适配器通过适配方式找到具体的控制器即处理器(后端控制器)
- 处理器执行完返回ModelAndView,处理器适配器将后端控制器的执行结果ModelAndView返还给前端控制器
- 前端控制器将ModelAndView传给ViewReslover视图解析器,由视图解析器后返还具体的view
- 前端控制器根据view进行视图渲染,并响应客户
- 常用注解
- Controller:SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中,如果使用@Controller注解标注的话,就需要使用
<!--配置注解扫描-->
<context:component-scan base-package="com.controller"/>
- RequestMapping:用于建立请求url和处理请求方法之间的对应关系
- 类上:URL的一级访问目录,以/开头,方便模块化管理
- 方法上:URL的二级访问目录,和一级目录组成一个完整的 URL 路径
- value:用于指定请求的URL。它和path属性的作用是一样的
- method:用来限定请求的方式
- params:用来限定请求参数的条件,如{"accountName"} 表示请求参数中必须有accountName;{"money!100"} 表示请求参数中money不能是100
- 访问页面或跳转时,WEB-INF下默认是安全资源,在其包下的资源不可以通过url直接获取,只可以在服务器内转发
3. SpringMVC请求
- springMVC可以接收的参数类型:基本参数类型、对象参数类型、数组参数类型、集合参数类型。
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2021/7/17
Time: 14:51
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>请求数据</title>
</head>
<body>
<%--不要有空格--%>
<a href="${pageContext.request.contextPath}/data?username=大明&age=19" >普通数据类型</a>
<a href="${pageContext.request.contextPath}/object?name=大明&id=2" >对象类型</a>
<form method="post" action="${pageContext.request.contextPath}/array">
<input type="checkbox" name="ids" value="1">1<br>
<input type="checkbox" name="ids" value="2">2<br>
<input type="checkbox" name="ids" value="3">3<br>
<input type="checkbox" name="ids" value="4">4<br>
<input type="checkbox" name="ids" value="5">5<br>
<input type="submit" value="数组元素">
</form>
<form method="post" action="${pageContext.request.contextPath}/listormap">
关键词 <input type="text" name="keyword">
用户id<input type="text" name="user.id">姓名<input type="text" name="user.name">
第一个集合<input type="text" name="userList[0].id"><input type="text" name="userList[0].name">
第二个集合<input type="text" name="userList[1].id"><input type="text" name="userList[1].name">
第一个map<input type="text" name="map['u1'].id"><input type="text" name="map['u1'].name">
第二个map<input type="text" name="map['u2'].id"><input type="text" name="map['u2'].name">
<input type="submit" value="集合数据类型">
</form>
<form method="post" action="${pageContext.request.contextPath}/date">
自定义转换器 生日<input type="text" name="date">
<input type="submit" value="自定义转换器 生日">
</form>
<a href="${pageContext.request.contextPath}/page?pageNo = 2" >对象类型</a>
</body>
</html>
package domain;
import java.util.List;
import java.util.Map;
public class QueryVo {
private String keyword;
private User user;
private List<User> userList;
private Map<String,User> map;
@Override
public String toString() {
return "QueryVo{" +
"keyword='" + keyword + '\'' +
", user=" + user +
", userList=" + userList +
", map=" + map +
'}';
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
public Map<String, User> getMap() {
return map;
}
public void setMap(Map<String, User> map) {
this.map = map;
}
}
package domain;
public class User {
private int id;
private String name;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
package domain;
public class User {
private int id;
private String name;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
package controller;
import domain.QueryVo;
import domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.Date;
@Controller
public class UserController {
@RequestMapping("/data")
public String data(String username,Integer age){
System.out.println(username);
System.out.println(age);
return "success";
}
@RequestMapping("/object")
public String object(User user){
System.out.println(user);
return "success";
}
@RequestMapping(path = "/array")
public String array(Integer[] ids){
System.out.println(Arrays.toString(ids));
return "success";
}
@RequestMapping("/listormap")
public String listormap(QueryVo queryVo){
System.out.println(queryVo);
return "success";
}
}
- controller中的业务方法会对参数值进行自动映射匹配和类型转换,将参数由string类型转为对应的要求类型
- 中文乱码过滤器:当post请求时数据会出现乱码,需要通过中文过滤器进行编码过滤
<!-- 中文过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 自定义转换器:springMVC提供了一些常用的类型转换器,对于特有的行为让那个开发者自定义处理
package converters;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ConverterDate implements Converter<String,Date> {
@Override
public Date convert(String birth) {
SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd");
Date date =null;
try {
date = sdf.parse(birth);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
<!-- 配置处理器适配器和处理器映射器 ,可以对json格式解析,进行了方法的增强-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!-- 配置自定义转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="converters.ConverterDate"/>
</set>
</property>
</bean>
package controller;
import domain.QueryVo;
import domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.Date;
@Controller
public class UserController {
@RequestMapping("/date")
public String date(Date date){
System.out.println(date);
return "success";
}
}
- 请求常用注解
- @RequestParam:当请求参数名与controller业务方法的参数名不一致时,可以显示绑定,设置默认值和数据非必须
- @RequestHeader:获取请求头数据
- @CookieValue:获取cookie中的数据
- 获取相关的Servlet相关API:SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,如request,response和session
package controller;
import domain.QueryVo;
import domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.Date;
@Controller
public class UserController {
@RequestMapping("/page")
// required 设置是否必须传递参数,默认值为true;如果设置了默认值,值自动改为false
public String page(@RequestParam(name="pageNo", defaultValue ="1", required = false) Integer pageNum, @RequestParam(defaultValue = "5") Integer pageSize){
System.out.println(pageNum);
System.out.println(pageSize);
return "success";
}
@RequestMapping("/header")
public String header(@RequestHeader("cookie") String cookie){
System.out.println(cookie);
return "success";
}
@RequestMapping("/cookie")
public String cookie(@CookieValue("JSESSIONID") String cookie){
System.out.println(cookie);
return "success";
}
@RequestMapping("/springAPI")
public String springAPI(HttpServletRequest request, HttpServletResponse response, HttpSession session){
System.out.println(request);
System.out.println(response);
System.out.println(session);
return "success";
}
}
4. springMVC响应
- 页面跳转方式包括返回字符串逻辑视图、void原始ServletAPI和ModelAndView方式
- void原始ServletAPI格式
// 原始Servlet
@RequestMapping("/servlet")
public void servlet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;utf-8");
response.getWriter().println("我收到额");
request.setAttribute("username", "原始servlet");
// request.getRequestDispatcher("success.jsp").forward(request, response);
}
- 返回的数据格式可以通过直接返回字符串数据方式或将对象、集合转为json格式返回
- 使用字符串逻辑视图实现页面的跳转实际上是执行请求转发,相当于forward
- forward关键字实现转发,则路径必须是实际视图URL,相当于 request.getRequestDispatcher("url").forward(request,response) ,既可以转发到jsp,也可以转发到其他的控制器方法
@RequestMapping("/forward")
public String forward(Model model) {
model.addAttribute("username", "转发");
return "forward:success.jsp";
}
- Redirect重定向实现重定向,路径必须是实际视图URL,虚拟目录springMVC框架自动完成拼接
@RequestMapping("/redirect")
public String redirect(Model model) {
model.addAttribute("username", "重定向");
// 重定向的页面不会展示username的值
return "redirect:success";
}
- ModelAndView有两种方式实现,推荐方式二
- 在Controller中方法创建并返回ModelAndView对象,并且设置视图名称
- 在Controller中方法形参上直接声明ModelAndView,无需在方法中自己创建,在方法中直接使用该对象设置视图,同样可以跳转页面
//ModelAndView方式一
@RequestMapping("/model1")
public ModelAndView model1() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username", "modelAndView方式一");
modelAndView.setViewName("success");
return modelAndView;
}
//ModelAndView方式二
@RequestMapping("/model2")
public ModelAndView model2(ModelAndView modelAndView) {
modelAndView.addObject("username", "modelAndView方式二");
modelAndView.setViewName("success");
return modelAndView;
}
- @SessionAttributes:适用于在多个请求之间共有数据,在控制器类上标注并配置需要在session中存放的数据,Spring MVC将存放在model中对应的数据暂存到HttpSession
@RequestMapping("/forward")
public String forward(Model model) {
model.addAttribute("username", "转发");
return "forward:success.jsp";
}
@RequestMapping("/returnString")
public String returnString() {
return "success";
}
5.静态资源的开启
- 问题:当有静态资源需要加载,如query文件,通过谷歌开发者工具抓包发现没有加载到jquery文件
- 原因:SpringMVC的前端控制器DispatcherServlet的url-pattern配置的是 /(缺省),代表对所有的静态资源都进行处理操作,这样就不会执行Tomcat内置的DefaultServlet处理
- 解决:配置文件放行静态资源
<!--方式一:在springmvc配置文件中指定放行资源-->
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/img/**" location="/img/"/>
<!--方式二(推荐):在springmvc配置文件中开启DefaultServlet处理静态资源-->
<mvc:default-servlet-handler/>