在 JavaEE 开发中,几乎全都是基于 B/S 架构的开发。在 B/S 架构中,系统标准的三层架构包括:表现层、业务层、持久层。
表现层:负责接收客户端请求,向客户端响应结果等,一般使用 MVC 模型
业务层:负责处理业务逻辑,调用持久层进行数据持久化等
持久层:负责数据持久化等
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。
Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块,使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring 的 Spring MVC 框架或集成其他 MVC 开发框架。
SpringMVC 的优势:
清晰的角色划分
扩展灵活
可适配性,通过 HandlerAdapter 可以支持任意的类作为处理器
可定制性,通过 HandlerMapping、ViewResolver 可以非常简单的定制
强大的 JSP 标签库,使 JSP 编写更容易
RESTful 风格的支持等
SpringMVC 和 Struts2 的对比:
相同点:
不同点:
需求:点击 index.jsp 页面的超链接,跳转到另一个页面并输出内容到控制台。
使用 IDEA 新建一个 Maven 工程,选择 maven-archetype-webapp
编辑 pom.xml,导入依赖
查看 pom.xml
<?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>cn.parzulpan</groupId>
<artifactId>SpringMVCStart</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>SpringMVCStart Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.1.20.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>SpringMVCStart</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
选中项目,点击右键,选择 Add FrameWorks Support
,添加上 SpringMVC 支持
配置 Tomcat,推荐版本 8 以上
编写 WEB-INF 目录下的 web.xml,配置一个 Servlet
查看 web.xml
<!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>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置 app 分派器(前端控制器) -->
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置初始化参数,读取 SpringMVC 的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/app-servlet.xml</param-value>
</init-param>
<!-- 配置 Servlet 对象的创建时间点为应用加载时创建,取值只能为非零整数,表示启动顺序 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置映射,同 Servlet 一样 -->
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
由于已经添加了 SpringMVC 支持,编写 WEB-INF 目录下 的 app-servlet.xml,即 SpringMVC 的配置文件
查看 app-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"><!-- 此文件负责整个 Spring MVC 的配置 -->
<!-- 配置 Spring 容器要扫描的包 -->
<context:component-scan base-package="cn.parzulpan"/>
<!-- 配置 视图解析器 -->
<bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 开启 Spring MVC 注解支持 -->
<mvc:annotation-driven/>
</beans>
编写控制器并使用注解配置,StartController.java
查看 StartController.java
package cn.parzulpan.web.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @Author : parzulpan
* @Time : 2020-12
* @Desc : 控制器,由于返回了结果,视图解析器会进行解析匹配,所以需要有对应的响应页面
*/
@Controller
@RequestMapping(path = "/say")
public class StartController {@RequestMapping(path = "/hello")
public String sayHello() {
System.out.println("SpringMVC Hello");
return "hello";
}
@RequestMapping(path = "/world")
public String sayWorld() {
System.out.println("SpringMVC World");
return "world";
}
}
编写对应响应页面
查看 响应页面
<!-- hello.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3> SpringMVC Hello !!! </h3>
</body>
</html>
<!-- world.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3> SpringMVC World !!! </h3>
</body>
</html>
编写测试文件,index.jsp
查看 index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body><h3> SpringMVC Start</h3>
<a href="say/hello">Say Hello</a>
<a href="say/world">Say World</a>
</body>
</html>
@RequestMapping
注解说明:
源码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
它的作用是于建立请求 URL 和处理请求方法之间的对应关系。
出现在类上,表示请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以 / 开头。出现在方法上,表示请求 URL 的第二级访问目录。
value / path 属性
用于指定请求的 URL
method 属性
用于指定请求的方式
params 属性
用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和配置的一模一样。
headers 属性
用于指定限制请求消息头的条件。
组件说明:
其中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
在 SpringMVC 配置文件中,使用 <mvc:annotation-driven>
可以自动加载 处理映射器 和 处理器适配器。
绑定机制:
k=v
格式的,比如 username=haha&password=123
支持的数据类型:
基本数据类型和字符串类型:
实体类型(JavaBean):
对象.属性
,例如 address.name
集合数据类型(List、Map等):
list[0].属性
,map['one'].属性
账户实体类 Account.java
查看 Account.java
public class Account implements Serializable {
private Integer id;
private String name;
private Float money;
private Address address;
// getter setter toString
}
账户地址实体类 Address.java
查看 Address.java
public class Address implements Serializable {
private String provinceName;
private String cityName;
// getter setter toString
}
用户实体类 User.java
查看 User.java
public class User implements Serializable {
private String username;
private String password;
private Integer age;
private List<Account> accounts;
private Map<String, Account> accountMap;
// getter setter toString
}
请求参数绑定的控制器 ParamsController.java
查看 ParamsController.java
@Controller
@RequestMapping(path = "/params")
public class ParamsController {
/**
* 基本数据类型和字符串类型
* @param username
* @param password
* @return
*/
@RequestMapping("/stringAndIntegerParams")
public String stringAndIntegerParams(String username, Integer password) {
System.out.println(username);
System.out.println(password);
return "hello";
}
/**
* 实体类型(JavaBean)
* @param account
* @return
*/
@RequestMapping("/javaBeanParams")
public String javaBeanParams(Account account) {
System.out.println(account);
return "hello";
}
/**
* 集合数据类型(List、Map等)
* @param user
* @return
*/
@RequestMapping("/collectionParams")
public String collectionParams(User user) {
System.out.println(user);
return "hello";
}
}
请求参数的绑定测试:params.jsp
查看 params.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>请求参数的绑定</title>
</head>
<body>
<a href="params/stringAndIntegerParams?username=parzulpan啊哈哈&password=1024">基本类型和 String 类型作为参数</a>
<br>
<form action="params/javaBeanParams" method="post">
账户名称:<input type="text" name="name" ><br/>
账户金额:<input type="text" name="money" ><br/>
账户省份:<input type="text" name="address.provinceName" ><br/>
账户城市:<input type="text" name="address.cityName" ><br/>
<input type="submit" value="保存">
</form>
<br>
<form action="params/collectionParams" method="post">
用户名称:<input type="text" name="username" ><br/>
用户密码:<input type="password" name="password" ><br/>
用户年龄:<input type="text" name="age" ><br/>
账户 1 名称:<input type="text" name="accounts[0].name" ><br/>
账户 1 金额:<input type="text" name="accounts[0].money" ><br/>
账户 2 名称:<input type="text" name="accounts[1].name" ><br/>
账户 2 金额:<input type="text" name="accounts[1].money" ><br/>
账户 3 名称:<input type="text" name="accountMap['one'].name" ><br/>
账户 3 金额:<input type="text" name="accountMap['one'].money" ><br/>
账户 4 名称:<input type="text" name="accountMap['two'].name" ><br/>
账户 4 金额:<input type="text" name="accountMap['two'].money" ><br/>
<input type="submit" value="保存">
</form>
</body>
</html>
对于 Post 请求(form 标签 method=post
):解决的方法是在 web.xml
中配置一个编码过滤器
<web-app>
<!-- 配置解决中文乱码的过滤器 -->
<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>
</web-app>
对于 Get 请求:解决的方法是修改 Tomcat 的 server.xml
配置文件,添加 <Connector useBodyEncodingForURI="true"/>
由于参数都是以字符串的形式传输,当把控制器中方法参数的类型改为 Date 时,就会出现错误:Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'
,为了解决这个问题,可以自定义一个类型转换器。
使用步骤:
定义一个类,实现 Converter 接口,该接口有<S, T>
两个泛型,S 表示接受的类型,T 表示目标类型
查看 StringToDateConverter.java
package cn.parzulpan.utils;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Author : parzulpan
* @Time : 2020-12
* @Desc : 自定义类型转换器
*/
public class StringToDateConverter implements Converter<String, Date> {@Override
public Date convert(String s) {
if (s.equals("")) {
throw new RuntimeException("请输入数据");
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
return sdf.parse(s);
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
在 SpringMVC 配置文件中配置类型转换器
在 annotation-driven
标签中引用自定义的类型转换服务
查看 app-servlet.xml
<!-- 配置自定义类型转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.parzulpan.utils.StringToDateConverter"/>
</set>
</property>
</bean><!-- 开启 Spring MVC 注解支持,并引用自定义的类型转换服务 -->
<mvc:annotation-driven conversion-service="conversionService"/> </code></pre></li>
测试
查看 CovertController.java
/**
* @Author : parzulpan
* @Time : 2020-12
* @Desc : 自定义类型转换器的控制器
*/
@Controller
@RequestMapping("/convert")
public class CovertController {@RequestMapping("/stringToDate")
public String stringToDate(Date date) {
System.out.println(date);
return "hello";
}
} 查看 converter.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>自定义类型转换器</title>
</head>
<body><a href="convert/stringToDate?date=2018-01-01">根据日期删除账户</a>
</body>
</html>
SpringMVC 还支持使用原始 ServletAPI 对象作为控制器方法的参数。支持原始 ServletAPI 对象有:
HttpServletRequest
HttpServletResponse
HttpSession
java.security.Principal
Locale
InputStream
OutputStream
Reader
Writer
/**
@Controller
@RequestMapping("/servletAPI")
public class ServletAPIController {
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
System.out.println(request);
System.out.println(response);
System.out.println(session);
return "world";
}
}
作用:
属性:
使用示例:
<!-- requestParams 注解的使用 -->
<a href="anno/useRequestParam?name=test">requestParam 注解</a>
@RequestMapping("/useRequestParam")
public String useRequestParam(@RequestParam("name") String username, @RequestParam(value="age",required=false) Integer age){
System.out.println(username + "," + age);
return "hello";
}
作用:
key=value&key=value...
结构的数据。get 请求方式不适用。属性:
使用示例:
post 请求 jsp 代码:
<!-- RequestBody 注解 -->
<form action="anno/useRequestBody" method="post">
用户名称:<input type="text" name="username" ><br/>
用户密码:<input type="password" name="password" ><br/>
用户年龄:<input type="text" name="age" ><br/>
<input type="submit" value="保存">
</form>
get 请求 jsp 代码:
<a href="anno/useRequestBody?body=test">requestBody 注解 get 请求</a>
@RequestMapping("/useRequestBody")
public String useRequestBody(@RequestBody(required=false) String body){
System.out.println(body);
return "hello";
}
作用:
/delete/{id}
,这个 {id}
就是 url 占位符。url 支持占位符是 Spring3.0 之后加入的。是 SpringMVC 支持 Restful URL 的一个重要标志。属性:
RESTful 是一种编程风格,它结构清晰,符合标准、易于理解、扩展方便。
我们知道,在 HTTP 协议里面,有四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
原来的方式:
@Controller()
@RequestMapping("/")
public class UserController() {
@RequestMapping("/user/findAll")
public String findAll(){};
@RequestMapping("/user/save")
public String save(){};
@RequestMapping("/user/update")
public String update(){};
@RequestMapping("/user/delete")
public String delete(Integer id){};
}
Restful 的方式:
@Controller()
@RequestMapping("/")
public class UserController() {
@RequestMapping(value="/user", method=RequestMethod.GET)
public String findAll(){};
@RequestMapping(value="/user", method=RequestMethod.POST)
public String save(){};
@RequestMapping(value="/user", method=RequestMethod.PUT)
public String update(){};
@RequestMapping(value="/user/{id}", method=RequestMethod.DELETE)
public String delete(@PathVariable("id") Integer id){};
@RequestMapping(value="/user", method=RequestMethod.DELETE)
public String delete(){};
}
使用示例:
<!-- PathVariable 注解 -->
<a href="anno/usePathVariable/100">pathVariable 注解</a>
@RequestMapping("/usePathVariable/{id}")
public String usePathVariable(@PathVariable("id") Integer id){
System.out.println(id);
return "hello";
}
作用:
属性:
使用示例:
<!-- RequestHeader 注解 -->
<a href="anno/useRequestHeader">获取请求消息头</a>
@RequestMapping("/useRequestHeader")
public String useRequestHeader(@RequestHeader(value="Accept-Language", required=false) String requestHeader){
System.out.println(requestHeader);
return "hello";
}
作用:
属性:
使用示例:
<!-- CookieValue 注解 -->
<a href="anno/useCookieValue">绑定 cookie 的值</a>
@RequestMapping("/useCookieValue")
public String useCookieValue(@CookieValue(value="JSESSIONID",required=false) String cookieValue){
System.out.println(cookieValue);
return "hello";
}
作用:
属性:
场景:
基于 JavaBean 属性的 使用示例:
<a href="anno/testModelAttribute?username=test">测试 ModelAttribute</a>
@ModelAttribute
public void showModel(User user) {
System.out.println("执行了 showModel 方法" + user.getUsername());
}
@RequestMapping("/testModelAttribute")
public String testModelAttribute(User user) {
System.out.println("执行了控制器的方法"+ user.getUsername());
return "hello";
}
基于 Map 的应用场景 ModelAttribute 修饰方法带返回值 使用示例:
<!-- 修改用户信息 -->
<form action="anno/updateUser" method="post">
用户名称:<input type="text" name="username" ><br/>
用户年龄:<input type="text" name="age" ><br/>
<input type="submit" value="保存">
</form>
// 查询数据库中用户信息
@ModelAttribute
public User showModel(String username) {
//模拟去数据库查询
User abc = findUserByName(username);
System.out.println("执行了 showModel 方法" + abc);
return abc;
}
// 模拟修改用户方法
@RequestMapping("/updateUser")
public String testModelAttribute(User user) {
System.out.println("控制器中处理请求的方法:修改用户:" + user);
return "hello";
}
// 模拟去数据库查询
private User findUserByName(String username) {
User user = new User();
user.setUsername(username);
user.setAge(19);
user.setPassword("123456");
return user;
}
基于 Map 的应用场景 ModelAttribute 修饰方法不带返回值 使用示例:
<!-- 修改用户信息 -->
<form action="anno/updateUser" method="post">
用户名称:<input type="text" name="username" ><br/>
用户年龄:<input type="text" name="age" ><br/>
<input type="submit" value="保存">
</form>
// 查询数据库中用户信息
@ModelAttribute
public void showModel(String username, Map<String, User> map) {
//模拟去数据库查询
User user = findUserByName(username);
System.out.println("执行了 showModel 方法" + user);
map.put("abc",user);
}
// 模拟修改用户方法
@RequestMapping("/updateUser")
public String testModelAttribute(@ModelAttribute("abc") User user) {
System.out.println("控制器中处理请求的方法:修改用户:"+user);
return "success";
}
// 模拟去数据库查询
private User findUserByName(String username) {
User user = new User();
user.setUsername(username);
user.setAge(19);
user.setPassword("123456");
return user;
}
作用:
属性:
使用示例:
<!-- SessionAttribute 注解的使用 -->
<a href="anno/testPut">存入 SessionAttribute</a>
<hr/>
<a href="anno/testGet">取出 SessionAttribute</a>
<hr/>
<a href="anno/testClean">清除 SessionAttribute</a>
@Controller
@RequestMapping("/anno")
@SessionAttributes(value ={"username", "password"}, types={Integer.class})
public class SessionAttributeController {
/**
* 把数据存入 SessionAttribute
* @param model
* @return
* Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
* 该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类
*/
@RequestMapping("/testPut")
public String testPut(Model model){
model.addAttribute("username", "parzulpan");
model.addAttribute("password", "123456");
model.addAttribute("age", 31);
// 跳转之前将数据保存到 username、password 和 age 中,因为注解@SessionAttribute 中有这几个参数
return "hello";
}
@RequestMapping("/testGet")
public String testGet(ModelMap model){
System.out.println(model.get("username") + "; " + model.get("password") + "; " + model.get("age"));
return "hello";
}
@RequestMapping("/testClean")
public String complete(SessionStatus sessionStatus){
sessionStatus.setComplete();
return "hello";
}
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章