Spring Mvc 进阶使用
一、 Spring Mvc的基础认识
MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。
1. mvc基础架构
2. mvc的实现原理
SpringMVC的具体执行流程:
当发起请求时被前置的控制器拦截到请求,根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,再将结果返回给请求者。
二、开始使用Springmvc
2.1 环境的搭建
基本步骤:
- 创建
maven
项目,并勾选出快速创建web环境项目选项(webapp)- 添加
pom
依赖- 编写
web.xml
文件- 编写
SpringMvc
相关xml
配置文件(如果是SSM还需要编写spring
的配置文件)- 创建并编写
Controller
相关代码- 配置
tomcat
(>7.0),并导入该项目
创建maven
项目,并勾选出快速创建web环境项目选项(webapp)
2. 添加pom
依赖
(此处应该有版本控制,不能想下面一样每个都写5.2.3… 像这样的版本号)
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
</dependencies>
3. 编写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_4_0.xsd"
version="4.0">
<!--配置DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联springmvc的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
</servlet>
<!--匹配servlet的请求,/标识匹配所有请求-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--/*和/都是拦截所有请求,/会拦截的请求不包含*.jsp,而/*的范围更大,还会拦截*.jsp这些请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4. 编写SpringMvc
相关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">
<!--处理映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!--视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置前缀-->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!--配置后缀-->
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="/hello" class="com.mashibing.controller.HelloController"></bean>
</beans>
** 5. 创建并编写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 HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//创建模型和视图对象
ModelAndView mv = new ModelAndView();
//将需要的值传递到model中
mv.addObject("msg","helloSpringMVC");
//设置要跳转的视图,
mv.setViewName("hello");
return mv;
}
}
6. 配置tomcat
(>7.0),并导入该项目
2.2 核心注解
标注在类上的注解:
核心注解 | 说明 |
---|---|
@Controller | - |
@RestController | - |
@RequestMapping | 设置整个控制层的请求前缀 |
@SessionAttributes | 此注解可以表示,当向request作用域设置数据的时候同时也要向session中保存一份,此注解有两个参数,一个value(表示将哪些值设置到session中),另外一个type(表示按照类型来设置数据,一般不用,因为有可能会将很多数据都设置到session中,导致session异常) |
标注在方法上的注解
核心注解 | 说明 |
---|---|
@RequestMapping | 指定 name属性,设置请求路径(根据method参数值,支持多种请求方式,默认都支持) |
@ResponseBody | 设置返回的方式,返回JSON 字符串。如果没有这个注解的话,就放回对应的视图 |
@GetMapping | 指定 name属性,设置请求路径,但只支持 Get 请求 |
@PostMapping | 和上述基本一直,但只支持 Post 请求 |
@DeleteMapping | 和上述基本一直,但只支持 Delete 请求 |
注意: 默认是不支持,put、delete
等请求的,这属于隐藏请求方式,需要自己手动开启(需要的话,自己可以百度自查,如何开启)
标注在参数上的注解
核心注解 | 说明 |
---|---|
@RequestParam | 指定请求的参数(一般通过请求url后的参数中获取,默认取相同名字的值)(建议指定相应的name) |
@RequestBody | 获取请求体中的值,(前端返回JSON数据格式,然后再通过转换成指定的对象格式) |
@PathVariable | 获取请求路径的值,默认取相同名字的值(建议指定相应的name) |
@RequestHeader | 获取请求头信息 |
@CookieValue | 获取cookie中的值 |
注意: 参数上指定了这些注解,默认是必传的参数,当然也可以设置参数为非必传(required=false)
3. 乱码问题
说明:
我们在表单或者发送请求的时候,经常会遇到中文乱码的问题,那么如何解决乱码问题呢?
GET请求:在server.xml文件中,添加URIEncoding=“UTF-8”
POST请求:编写过滤器进行实现
解决方案:在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_4_0.xsd"
version="4.0">
<!--配置DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
关联springmvc的配置文件:
此配置文件的属性可以不添加,但是需要在WEB-INF的目录下创建 前端控制器名称-servlet.xml文件
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
</servlet>
<!--匹配servlet的请求,
/:标识匹配所有请求,但是不会jsp页面
/*:拦截所有请求,拦截jsp页面
但是需要注意的是,当配置成index.html的时候,会发现请求不到
原因在于,tomcat下也有一个web.xml文件,所有的项目下web.xml文件都需要继承此web.xml
在服务器的web.xml文件中有一个DefaultServlet用来处理静态资源,但是url-pattern是/
而我们在自己的配置文件中如果添加了url-pattern=/会覆盖父类中的url-pattern,此时在请求的时候
DispatcherServlet会去controller中做匹配,找不到则直接报404
而在服务器的web.xml文件中包含了一个JspServlet的处理,所以不过拦截jsp请求
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--解决post请求乱码-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!--解决响应乱码-->
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
2.4 对Servlet原生API的支持
HttpSession
、HttpServletRequest
、HttpServletResponse
等一系列API
(如果想更加深入理解Servlet 原生API的使用,可以自己查询相关文章)
2.5 参数和页面的传递(ModelAndView
)
直接上案例
@Controller
public class OutputController {
@RequestMapping("mv")
public ModelAndView mv(){
ModelAndView mv = new ModelAndView();
mv.setViewName("output"); // 设置视图页面
mv.addObject("msg","hello.modelAndView"); // 添加返回参数
return mv;
}
}
2.6 页面转发和重定向
此功能主要是由 视图解析器
完成的功能
使用案例:(forward
、redirect
)
/**
* 当使用转发的时候可以添加前缀forward:index.jsp,此时是不会经过视图解析器的,所以要添加完整的名称
* forward:也可以由一个请求跳转到另外一个请求
*/
@RequestMapping("/forward01")
public String forward(){
System.out.println("1");
return "forward:/index.jsp";
}
/**
* redirect :重定向的路径
* 相当于 response.sendRedirect("index.jsp")
* 跟视图解析器无关
*/
@RequestMapping("redirect")
public String redirect(){
System.out.println("redirect");
return "redirect:/index.jsp";
}
2.7 静态资源访问
当页面中包含静态资源的时候我们能够正确的获取到吗?
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
pageContext.setAttribute("ctx",request.getContextPath());
%>
<html>
<head>
<title>Title</title>
</head>
<body>
hello springmvc
<img src="${ctx}/images/timg.jpg">
</body>
</html>
在springmvc.xml
中添加相关配置
<!--
此配置表示 我们自己配置的请求由controller来处理,但是不能请求的处理交由tomcat来处理
静态资源可以访问,但是动态请求无法访问
-->
<mvc:default-servlet-handler/>
<!--保证静态资源和动态请求都能够访问-->
<mvc:annotation-driven/>
## 三、高级使用 ### 3.1 返回JSON数据
相关注解:@ResponseBody
、@RestController
3.2 获取请求体 - @RequestBody
注意:一个请求只能有一个请求体
请求的参数,都是放在请求体中的。
与@RequestParam
不同。
3.3 文件处理
springmvc
默认是不添加文件组件的(九大组件)
在springmvc.xml
的配置中,应该添加上:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="1024000"></property>
</bean>
文件上传:
@Controller
public class FileController {
@RequestMapping("/download")
public ResponseEntity<byte[]> download(HttpServletRequest request) throws Exception {
//获取要下载文件的路径及输入流对象
ServletContext servletContext = request.getServletContext();
String realPath = servletContext.getRealPath("/script/jquery-1.9.1.min.js");
FileInputStream fileInputStream = new FileInputStream(realPath);
byte[] bytes = new byte[fileInputStream.available()];
fileInputStream.read(bytes);
fileInputStream.close();
//将要下载文件内容返回
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Content-Disposition","attachment;filename=jquery-1.9.1.min.js");
return new ResponseEntity<byte[]>(bytes,httpHeaders,HttpStatus.OK);
}
}
文件下载:
@Controller
public class FileController {
@RequestMapping(value = "/testUpload", method = RequestMethod.POST)
public String testUpload(@RequestParam(value = "desc", required = false) String desc,
@RequestParam("file") MultipartFile multipartFile) throws IOException {
System.out.println("desc : " + desc);
System.out.println("OriginalFilename : " + multipartFile.getOriginalFilename());
multipartFile.transferTo(new File("D:\\file\\"+multipartFile.getOriginalFilename()));
return "success"; //增加成功页面: /views/success.jsp
}
}
3.4 国际化操作
核心步骤:
- 实现接口
LocaleResolver
springmvc.xml
配置文件中,添加进入容器中
四、进阶使用
4.1. 自定义视图解析器 – ViewResolver
相关接口:视图解析器 ViewResolver
和 视图 View
使用案例
- 自定义视图:实现
View
接口
public class MyView implements View {
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("保存的对象是:"+model);
response.setContentType("text/html");
response.getWriter().write("欢迎加入马士兵教育");
}
/**
* 返回数据内容的类型
* @return
*/
public String getContentType() {
return "text/html";
}
}
- 自定义视图解析器:实现
ViewResolver
接口
public class MyViewResolver implements ViewResolver, Ordered {
private int order = 0;
public View resolveViewName(String viewName, Locale locale) throws Exception {
//如果前缀是msb:开头的就进行解析
if (viewName.startsWith("msb:")){
System.out.println("msb:");
return new MyView();
}else{
//如果不是,则直接返回null
return null;
}
}
public int getOrder() {
return this.order;
}
public void setOrder(Integer order) {
this.order = order;
}
}
- 在
springmvc.xml
配置文件中添加进自定义视图解析器
(在初始化视图解析器时,会根据对象类型获取Bean对象。因此只要将视图解析器,注入IOC容器中即可)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.mashibing"></context:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean class="com.mashibing.view.MyViewResolver">
<property name="order" value="1"></property>
</bean>
</beans>
4.2. 自定义类型转换器 – Converter
相关接口:
使用案例:
- 创建一个实体类:
User.java
@Setter
@Getter
public class User {
private Integer id;
private String name;
private Integer age;
private String gender;
}
- 创建自定义转换器:
MyConverter.java
@Component
public class MyConverter implements Converter<String, User> {
public User convert(String source) {
User user = null;
String[] split = source.split("-");
if (source!=null && split.length==4){
user = new User();
user.setId(Integer.parseInt(split[0]));
user.setName(split[1]);
user.setAge(Integer.parseInt(split[2]));
user.setGender(split[3]);
}
return user;
}
}
- 在
springmvc.xml
的配置文件中添加装换器
(转换器不是mvc中的九大组件之一,不会从IOC容器中获取转换器)
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="myConverter"></ref>
</set>
</property>
</bean>
适用场景:
4.3. 自定义日期格式装换器 – @DateTimeFormat
有时候我们经常需要在页面添加日期等相关信息,此时需要制定日期格式化转换器,此操作非常简单:只需要在单独的属性上添加@DateTimeFormat
注解即可,制定对应的格式
4.4. 数据校验
一般情况下我们会在前端页面实现数据的校验,但是大家需要注意的是前端校验会存在数据的不安全问题,因此一般情况下我们都会使用前端校验+后端校验的方式,这样的话既能够满足用户的体验度,同时也能保证数据的安全,下面来说一下在springmvc中如何进行后端数据校验。
JSR303是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 6.0 中 。JSR 303 (Java Specification Requests意思是Java 规范提案)通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对 Bean 进行验证。
JSR303:
Hibernate Validator 扩展注解:
使用案例
- 导入pom相关依赖:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.0.Final</version>
</dependency>
- 编写实体类:
User.java
@Data
public class User {
private Integer id;
@NotNull
@Length(min = 5,max = 10)
private String name;
private Integer age;
private String gender;
@Past
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birth;
@Email
private String email;
}
- 编写controller代码:
DataValidateController.java
@Controller
public class DataValidateController {
@RequestMapping("/dataValidate")
public String validate(@Valid User user, BindingResult bindingResult) {
System.out.println(user);
if (bindingResult.hasErrors()) {
System.out.println("验证失败");
return "redirect:/index.jsp";
} else {
System.out.println("验证成功");
return "hello";
}
}
}
- 编写页面:
form.jsp
<%--
Created by IntelliJ IDEA.
User: root
Date: 2020/3/12
Time: 15:23
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="dataValidate" method="post">
编号:<input type="text" name="id"><br>
姓名:<input type="text" name="name"><br>
年龄:<input type="text" name="age"><br>
性别:<input type="text" name="gender"><br>
日期:<input type="text" name="birth"><br>
邮箱:<input type="text" name="email"><br>
<input type="submit" value="提交">
</form>
</body>
</html>