1.简介
2.HelloWorld程序
3.Spring MVC的执行流程
4.对静态资源访问
5.注解的开发方式
6.响应传值
7.SpringMVC对JSON的支持
8.格式化JSON
一、简介
1.什么是MVC模型
MVC模型:是一种架构型的模式,本身不引入新功能,只是帮助我们将开发的结构组织的更加合理,使展示与模型分离、流程控制逻辑、业务逻辑调用与展示逻辑分离------>责任分离。
在CS架构标准的MVC中模型能主动推数据给视图进行更新(观察者设计模式,在模型上注册视图,当模型更新时自动更新视图),但在Web开发中模型是无法主动推给视图(无法主动更新用户界面),因为在Web开发是请求-响应模型。
2.什么是Spring MVC
MVC框架,它解决WEB开发中常见的问题(参数接收、页面跳转 、文件上传、表单验证、国际化、等等),而且使用简单,与Spring无缝集成。
Spring3.0 后全面超越 Struts2,成为最优秀的 MVC 框架 (更安全,性能更好,更简单)。
支持 RESTful风格的 URL 请求 。
采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。
3.前端控制器
Front Controller模式要求在WEB应用系统的前端(Front)设置一个入口控制器(Controller),所有的request请求都被发往该控制器统一处理,处理所有请求共同的操作。
二、HelloWorld程序
1、在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>com.xj</groupId>
<artifactId>SMvc</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<properties>
<project.spring.verison>5.1.5.RELEASE</project.spring.verison>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${project.spring.verison}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${project.spring.verison}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${project.spring.verison}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>
2、配置控制器HelloController
package com.xj._01_hello;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by Administrator on 2019/12/30 0030.
*/
public class HelloController implements Controller{
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
System.out.println("Hello SpringMVC!!!");
ModelAndView mv = new ModelAndView();
//跳转视图
mv.setViewName("/hello.jsp");//将数据共享到前台页面
mv.addObject("msg","你好");
return mv;
}
}
3、新建mvc.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 name="/hello" class="com.xj._01_hello.HelloController"></bean>
</beans>
4、在web.xml文件中配置前端控制器
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!--配置前端控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联SpringMVC的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mvc.xml</param-value>
</init-param>
<!--Tomcat启动时完成初始化-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--通过访问什么路径的url,就可以进入前端控制器-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
5、hello.jsp
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2019/12/30 0030
Time: 20:36
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>
Spring MVC!!!
${msg}
</body>
</html>
启动Tomcat,访问hello.jsp
三、Spring MVC的执行流程
SpringMVC流程:
01、用户发送出请求到前端控制器DispatcherServlet。
02、DispatcherServlet收到请求调用HandlerMapping(处理器映射器)。
03、HandlerMapping找到具体的控制器(可查找xml配置或注解配置),生成处理器对象的执行链(如果有),再一起返回给DispatcherServlet。
04、DispatcherServlet调用HandlerAdapter(处理器适配器)。
05、HandlerAdapter经过适配调用具体的处理器(controller)。
06、Controller执行完成返回ModelAndView对象。
07、HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
08、DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)。
09、ViewReslover解析后返回具体View(视图)。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、DispatcherServlet响应用户。
涉及组件分析:
1、前端控制器DispatcherServlet(不需要程序员开发),由框架提供,在web.xml中配置。
作用:接收请求,响应结果,相当于转发器,中央处理器。
2、处理器映射器HandlerMapping(不需要程序员开发),由框架提供。
作用:根据请求的url查找Handler(处理器/Controller),可以通过XML和注解方式来映射。
3、处理器适配器HandlerAdapter(不需要程序员开发),由框架提供。
作用:按照特定规则(HandlerAdapter要求的规则)去执行Controller。
4、控制器Controller(需要工程师开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。
作用:接受用户请求信息,调用业务方法处理请求,也称之为后端控制器。
5、视图解析器ViewResolver(不需要程序员开发),由框架提供
作用:进行视图解析,把逻辑视图名解析成真正的物理视图。
SpringMVC框架支持多种View视图技术,包括:jstlView、freemarkerView、pdfView等。
6、视图View(需要工程师开发)
作用:把数据展现给用户的页面 View是一个接口,实现类支持不同的View技术(jsp、freemarker、pdf等)
四、对静态资源的访问
我们这样的配置有这样一个问题: 在Web根路径添加index.html,然后不能访问,原因是什么呢?为什么此时在配置前端控制器的URL模式(<url-pattern>)写成 / 就不行呢?
原因:
Tomcat中处理静态资源访问的servlet(default)的映射路径为/.
在启动项目的时候,在Tomcat中的web.xml是先加载的,项目的web.xml是后加载的,如果配置了相同的映射路径,后面的会覆盖前者.
也就是说,SpringMVC中的DispatcherServlet的映射路径覆盖了Tomcat默认对静态资源的处理的路径。
如果SpringMVC要配置为/,那么就得设置Dispatcherservlet对静态资源进行支持。
解决方案:需要在SpringMVC的配置文件中添加对静态资源的访问 <mvc:default-servlet-handler/>
或者 /改成 *.do
<mvc:default-servlet-handler/> 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,它会对进入 DispatcherServlet 的请求进行筛查,如果发现是没有经过映射的请求,就将该请求交由 Tomcat默认的 Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理
/和/*的区别:
/ 会匹配url请求/index等 ,也会匹配静态资源*.js,*.html等, 但不会匹配*.jsp文件。
/* 会匹配url请求/index等 ,也会匹配静态资源*.js,*.html等, 会匹配*.jsp文件。如果使用JSP,直接响应JSP代码,没有渲染.(不建议)
五、注解的开发方式
1、配置前端控制器(参考上面)
2、配置控制器
package com.xj._02_anno;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
/**
* Created by Administrator on 2019/12/30 0030.
*/
@Controller
public class AnnoController {
@RequestMapping("/list")
public ModelAndView list(){
System.out.println("这是注解的方式");
return null;
}
}
3、配置IoC和MVC注解解析器
<?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:mvc="http://www.springframework.org/schema/mvc"
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/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">
<!--配置控制器-->
<bean name="/hello" class="com.xj._01_hello.HelloController"></bean>
<!-- 配置对静态资源的访问-->
<mvc:default-servlet-handler/>
<!--IoC注解解析器-->
<context:component-scan base-package="com.xj" />
<!--MVC注解解析器-->
<mvc:annotation-driven/>
</beans>
访问list页面,控制台输出
Java EE应用程序分为三层:
控制层(Web) @Controller
业务逻辑层(Service) @Service
数据持久层(DAO) @Resposotory
其他组件使用通用注解 @Component
注意:
1):四者的功能一模一样,仅仅只是被贴的组件类型不同.
2):作用,就是把被贴的类交给Spring管理,创建出对象,如下.
<bean id=”类简单名字,首字母小写” class=”类的全限定名称”/>
SpringMVC注解的解析器: <mvc:annotation-driven>:
会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter、ExceptionHandlerExceptionResolver三个bean。
除此之外,还支持:
支持使用 ConversionService实例对表单参数进行类型转换.
支持使用 @NumberFormat、@DateTimeFormat注解完成数据格式化操作.
支持使用 @Valid注解对JavaBean实例进行JSR303验证.
支持使用 @RequestBody和@ResponseBody注解读写JSON.
@RequestMapping注解: 设置Controller方法的访问URL,不能重名.
一:URL路径映射 @RequestMapping("/list")
二:窄化请求映射 @RequestMapping("employee/list")
三:请求方法限定: @RequestMapping(value="/list",method=RequestMethod.POST)
假如多个类中,都有相同的list方法,就可以窄化请求映射
如果一个类中有多个方法,可以将窄化请求提出来,在类中的上面添加@RequestMapping(/employee)
小结
1.使用注解开发SpringMVC必须首先要配置mvc的注解解析器和IoC的注解解析器
2.@RequestMapping注解用于指定对应的url请求路径,value的值表示路径,路径通常以"/"开头,"/"可以省略.
3.@RequestMapping可以标注在类中,用于窄化请求映射.此时访问资源的路径为:"/类的路径/方法的路径"
4.@RequestMapping可以添加method属性,用于限定请求请求后台资源的方法.
六、响应传值
情况一:Controller方法的返回值类型为void:
此时就是把Controller当做Servlet来用(不用).
在Controller方法形参上可以定义request和response,使用request或response指定响应结果:
①:使用request请求转发页面: request.getRequestDispatcher("页面路径").forward(request, response);
②:通过response重定向页面: response.sendRedirect("url")
③:通过response指定响应结果,例如响应json数据如下: 通过request.setAttribute("key","value")共享数据
package com.xj._03_response;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by Administrator on 2019/12/30 0030.
*/
@Controller
public class ResponseController {
@RequestMapping("/test1")
public void test1(HttpServletRequest request, HttpServletResponse response) throws Exception{
//共享数据
request.setAttribute("msg","你好");
//页面跳转
request.getRequestDispatcher("/WEB-INF/view/response/response.jsp").forward(request,response);
}
}
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2019/12/30 0030
Time: 22:55
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>
响应传值的页面!
${msg}
</body>
</html>
情况二:返回ModelAndView类型和共享数据(运用比较多).
Controller方法中定义ModelAndView对象并返回,对象中设置model数据、指定view。
@RequestMapping("/test2")
public ModelAndView test2(){
ModelAndView mv = new ModelAndView();
//共享数据
mv.addObject("msg","我不好");
//默认的key为数据类型的首字母小写
mv.addObject("为啥不好");
//key值相同的数据,后一个会覆盖掉之前的数据
mv.addObject(20);
mv.addObject(30);
//跳转页面
mv.setViewName("/WEB-INF/view/response/response.jsp");
return mv;
}
${msg}${string}${integer}
重新配置视图解析器:
Controller方法返回字符串表示逻辑视图名,通过视图解析器解析为物理视图地址。 此时默认的物理视图地址为:视图前缀+逻辑视图名称+视图后缀.
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--设置视图前缀-->
<property name="prefix" value="/WEB-INF/view/"/>
<!--设置视图后缀-->
<property name="suffix" value=".jsp"/>
</bean>
//跳转页面
mv.setViewName("response/response");
注:不适用于第一种情况
情况三:返回String类型和共享数据(使用广泛).
返回值为String类型,即为逻辑视图名,此时默认视图的地址:前缀+方法的返回值+后缀
使用参数中的Model对象共享数据:
@RequestMapping("/test3")
public String test3(Model model){
model.addAttribute("msg","为啥好");
return "response/response";
}
假如有一个User类
package com.xj._03_response;
/**
* Created by Administrator on 2019/12/31 0031.
*/
public class User {
private String name;
private Integer age;
public User(){}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
User user = new User();
user.setName("张三");
user.setAge(13);
model.addAttribute(user);
${user}${user.age}
redirect和forward: redirect和forward: redirect方式相当于“response.sendRedirect()”,转发后浏览器的地址栏变为重定向后的地址,不共享之前请求的数据。 forward方式相当于“request.getRequestDispatcher().forward(request,response)”,转发后浏览器地址栏还是原来的地址,共享之前请求中的数据。 redirect或者forward之后,配置的视图解析器中的前缀和后缀不再有效.
return "forward:hello.jsp";
return "redirect:hello.jsp";
情况四:返回对象类型和共享数据(把当前请求的url作为逻辑视图名称).
//浏览器请求该方法时,会跳转到test.jsp页面(当前请求的url),
//并将user对象共享到前台,共享的对象的默认key值为:简单类名,首字母小写
@RequestMapping("/test4")
public User test4(){
return new User("李四",22);
}
解决方法: 可以使用@ModelAttribute注解修改共享对象的key值
七、SpringMVC对JSON的支持
将对象转换为json的方法有很多,可以使用工具类处理 有两种:
一种是springMVC底层使用的jackson
另外一个中为阿里出品,fastjson
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
@RequestMapping("/test5")
@ResponseBody //可以把方法返回的对象,转成JSON格式的字符串,响应给方法的返回者
public User test5(){
return new User("王五",30);
}
八、格式化JSON
假如有个Employee类有一些属性,但是不想显示password信息。
package com.xj._03_response;
import lombok.*;
import java.util.Date;
/**
* Created by Administrator on 2019/12/31 0031.
*/
@Setter@Getter@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private Integer id;
private String name;
private Integer age;
private Date birthday;
private String password;
private Boolean sex;
}
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
解决方法:在实体类的属性上面添加注解
假如想更改属性的名字
假如想以日期的形式显示数据
假如不知道注解,解决方法,在实体类中添加一个方法如下
public Map toJsonMap(){
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Map map = new HashMap();
map.put("id",this.id);
map.put("name",this.name);
map.put("age",this.age);
map.put("birthday",format.format(this.birthday));
map.put("gender",this.sex);
//password没写
return map;
}
@RequestMapping("/test6")
@ResponseBody //可以把方法返回的对象,转成JSON格式的字符串,响应给方法的返回者
public Object test6(){
Employee employee = new Employee(1, "赵柳", 12, new Date(), "123", true);
return employee.toJsonMap();
}