一、Spring Web框架
MVC思想
Spring MVC
Servlet:Web 服务的模块,包含对 MVC 与 REST 的实现,Spring MVC。
Web:提供与 Web 的集成,基于 Web 应用程序上下文。
WebSocket:实现客户端与服务端主动通信。
Portlet:提供了在 Portlet 环境中实现 MVC。
它解决 Web 开发中常见的问题(参数接收、文件上传、表单验证、国际化等),而且使用简单,与 Spring无缝集成。
Spring3.0 后全面超越 Struts2,成为最优秀的 MVC 框架 (更安全,性能更好,更简单)。
支持 RESTful 风格的 URL 请求 ,非常容易与其他视图技术集成,如 Velocity、FreeMarker、JSP 等。
采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。
-
Spring FrameWork体系
二、前端控制器
在MVC框架中都存在一个前端控制器,在WEB应用的前端(Front)设置一个入口控制器(Controller)
what
是用来提供一个集中的请求处理机制,所有的请求都被发往该控制器统一处理,然后把请求分发给各自相应的处理程序
do
一般用来做一个共同的处理,如权限检查,授权,日志记录等
why
因为前端控制的集中处理请求的能力,因此提高了可重用性和可拓展性
Spring MVC中的前端控制器
- 其提供了 DispatcherServlet 类作为前端控制器,要使用Spring MVC必须在 web.xml 中配置前端控制器
- 把处理请求的对象称之为处理器或后端控制器,Spring MVC中习惯称之为Controller,如处理员工请求的就会命名为
EmployeeController
。
三、 开发步骤
打包方式是war
添加依赖
<properties>
<spring.version>5.0.8.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8080</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
配置前端控制器
- web.xml
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 指定启动容器的 Spring 配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mvc.xml</param-value>
</init-param>
<!-- Tomcat 启动完之后就帮我们初始化这个servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置映射路径 -->
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 配置如.do、.htm 是最传统方式,可以访问静态文件(jpg、 js、 css),但不支持 RESTful 风格。
- 配置成 /,可以支持流行的 RESTful 风格,但会导致静态文件(jpg、 js、 css)被拦截后不能访问。
怎么让静态资源可以访问到:
在 Spring MVC的配置文件中配置<mvc:default-servlet-handler/>
即可。
上述配置会在Spring MVC上下文中定义一个DefaultServletHttpRequestHandler,它会对进入DispatcherServlet 的请求进行筛查,若不是映射的请求,就将该请求交由容器默认的Servlet处理。
-
配置成 /*,是错误的方式,可以请求到 Controller 中,但跳转到调转到 JSP 时被拦截,不能渲染 JSP 视图,也会导致静资源访问不了。
编写一个处理器类及JSP
编写Spring MVC配置文件
-
mvc.xml
mvc.xml
四、处理响应
找视图文件和往作用域中存入数据
返回ModelAndView
返回String
消除视图前缀和后缀
- mvc.xml
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property> <!-- 视图前缀 -->
<property name="suffix" value=".jsp"></property> <!-- 视图后缀 -->
</bean>
视图就是:前缀+逻辑视图名+后缀名
五、 请求转发及URL重定向
请求转发
加上forward前缀方式,表示请求转发,相当于request.getRequestDispatcher().forward(request,response)
,转发后浏览器地址栏不变,共享之前请求中的数据。
@RequestMapping("/f")
public String forward() {
// 不会使用到视图解析器的前缀与后缀
//return "forward:/WEB-INF/views/03.f_r.jsp";
//也可以转发到控制器里的方法路径
return "forward:/resp1";
}
URL重定向
redirect前缀方式,表示重定向,相当于response.sendRedirect()
,重定向后浏览器地址栏变为重定向后的地址,不共享之前请求的数据。
@RequestMapping("/r")
public String redirect() {
// 不会使用到视图解析器的前缀与后缀
//return "redirect:/01.static.html";
//也可以重定向到控制器里的方法路径
return "redirect:/resp2";
}
路径问题
/response/test6.do ---> “redirect:/hello.html” ---> localhost:/hello.html
/response/test6.do ---> “redirect:hello.html” ---> localhost:/response/hello.html
六、 处理简单类型请求参数
请求参数名 和 处理方法方法的形参 不同名时使用 @RequestParam
// /req1.do?username=xx&age=11
@RequestMapping("/req1")
public ModelAndView rep1(@RequestParam("username")String name, int age) {
System.out.println(name);
System.out.println(age);
return null; // 不找视图,不往作用域里存数据
}
乱码处理
-
get方式传递中文参数乱码问题
使用 Maven 的话,可以 pom.xml 中的tomcat 插件配置一行这个也可以解决<uriEncoding>UTF-8</uriEncoding>
Tomcat 8已处理这个问题,不需要额外配置 -
post方法传递中文乱问题
直接使用Spring MVC内置的过滤器来处理。
web.xml
<!-- 针对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>
七、处理复合类型请求参数
数组类型参数
// /req2.do?ids=1&ids=2&ids=3 使用环境:比如批量删除
@RequestMapping("/req2")
public ModelAndView req2(Long[] ids) {
System.out.println(Arrays.toString(ids));
return null; // 不找视图,不往作用域里存数据
}
JavaBean类型参数
@RequestMapping("/req3")
/*反射创建User对象,遍历这个对象属性username, password id
* req.getParameter("属性名") 转型后设置到这个User对象属性上
* */
public ModelAndView req3(User user) {
System.out.println(user);
return null; // 不找视图,不往作用域里存数据
}
八、处理日期类型请求参数
处理日期格式参数
- 在Controller形参贴上
@DateTimeFormat
// /req4.do?date=2020-05-01
@SuppressWarnings("deprecation")
@RequestMapping("/req4")
public ModelAndView req4(@DateTimeFormat(pattern="yyyy-MM-dd")Date date) {
System.out.println(date.toLocaleString());
return null; // 不找视图,不往作用域里存数据
}
- 在封装参数类的Date类型的字段上贴
@DateTimeFormat
省略了setter和getter方法
九、ModelAttribute注解使用
项目中用于查询条件回显用
// /req5.do?keyword=x&minAge=1&maxAge=18
@RequestMapping("/req5")
public String req5(@ModelAttribute("qo")UserQueryObject qo) { // model.addAttribute("userQueryObject",查询对象)
System.out.println(qo);
return "04.m";
}
在JSP中可通过${qo}
获取
十、 文件上传
添加依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
准备上传表单
:multipart/form-data
,且是POST
。
<form action="/upload.do" method="POST" enctype="multipart/form-data">
姓名:<input type="text" name="username"/><br/>
年龄:<input type="text" name="age"/><br/>
文件:<input type="file" name="pic"><br>
<input type="submit" value="提交"/>
</form>
配置上传解析器
multipartResolver
- mvc.xml
<!-- 配置上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="102400"></property>
</bean>
编写上传控制器
@Controller
public class UploadController {
@Autowired
private ServletContext servletContext;
// 在调用这个方法之前String MVC 会使用上传解析器帮你把上传的文件的内容封装成MultipartFile
@RequestMapping("/upload")
public ModelAndView upload(String username, int age, MultipartFile pic) throws IOException {
System.out.println(username);
System.out.println(age);
System.out.println(pic.getContentType());// 文件类型
System.out.println(pic.getName());// 上传文件的参数名name="pic"
System.out.println(pic.getOriginalFilename());// 文件名
System.out.println(pic.getSize());// 文件大小
System.out.println(pic.getInputStream());// 文件输入流
System.out.println(pic.getClass());// pic实现类
// 根据项目上传文件的相对路径获取其绝对路径
String uploadDir = servletContext.getRealPath("/uploaddir");
System.out.println(uploadDir);
// 获取文件后缀名
String suffix = pic.getOriginalFilename().substring(pic.getOriginalFilename().lastIndexOf("."));
System.out.println(suffix);
// 第一个参数是源,第二个参数是目标
FileCopyUtils.copy(pic.getInputStream(), new FileOutputStream(uploadDir+"/"+UUID.randomUUID().toString() + suffix));
return null;
}
}
十一、 拦截器
- Spring MVC 提供的,若配置在Spring MVC配置文件中,则被Spring容器管理,主要用于对请求访问控制器的方法进行拦截
- 项目中用于登录与权限判断
定义一个类实现HandlerInterceptor
public class MyHandlerInterceptor implements HandlerInterceptor {
// 前置拦截,在控制器方法执行之前执行
// 如果是false , 阻止执行
// 如果是true , 执行放行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle");
return false;
}
// 后置拦截,处理方法之后,渲染视图之前
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
// 渲染视图之后
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion");
}
}
配置拦截器
被排除的路径
<mvc:exclude-mapping path="/index.html"/>
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 映射路径,对哪些路径需要拦截 -->
<mvc:mapping path="/**"/>
<!-- 拦截处理器类 -->
<bean class="cn.wolfcode.web.interceptor.MyHandlerInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
十二、核心组件说明
不需要我们开发
- 前端控制器DispatcherServlet
不需要我们开发,由框架提供,需要在web.xml中配置。作用:接受请求,处理响应结果,转发器,中央处理器。 - 处理器映射器HandlerMapping
不需要我们开发,由框架提供。作用,更具请求的URL找到对应的Handler。 - 处理器适配器HandlerAdapter
不要我们开发,由框架提供。作用:调用处理器(Handler / Controller)的方法。 - 视图解析器ViewResolver
不需要我们开发,有框架或者第三方提供。作用:视图解析,把逻辑视图名称解析成真正的物理视图。支持多种视图技术Velocity、FreeMarker、JSP等。
需要我们开发
- 处理器Handler(又名Controller),后端控制器
必须按照HandlerAdapter的规范去开发。作用:接收用户请求数据,调用业务方法处理请求。 - 视图
需要我们开发。作用:把数据展现给用户。
开发步骤
- 1、配置前端控制器
- 2、配置处理器映射器、处理适配器、视图解析器(用默认的可不配置)。
- 3、需要开发(结合需求):
先开发Contoller,再配置。
开发JSP。
十三、 执行流程分析
- 用户发送出请求到前端控制器 DispatcherServlet。
- DispatcherServlet 收到请求调用 HandlerMapping(处理器映射器)。
- HandlerMapping 找到具体的处理器(通过 XML 或注解配置),生成处理器对象及处理器拦截器(若有),再一起返回给 DispatcherServlet。
- DispatcherServlet 调用 HandlerAdapter(处理器适配器)。
- HandlerAdapter 经过适配调用具体的处理器的某个方法(Handler/Controller)。
- Controller 执行完成返回 ModelAndView 对象。
- HandlerAdapter 将 Controller 返回的 ModelAndView 再返回给 DispatcherServlet。
- DispatcherServlet 将 ModelAndView 传给 ViewReslover(视图解析器)。
- ViewReslover 解析后返回具体 View(视图)。
- DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中)。
- DispatcherServlet 响应用户。
网友评论