一、概念

1.什么是SpringMVC

它是基于MVC开发模式的框架,用来优化控制器.它是Spring家族的一员.它也具备IOC和AOP.

什么是MVC?
它是一种开发模式,它是模型视图控制器的简称.所有的web应用都是基于MVC开发.
M:模型层,包含实体类,业务逻辑层,数据访问层
V:视图层,html,javaScript,vue等都是视图层,用来显现数据
C:控制器,它是用来接收客户端的请求,并返回响应到客户端的组件,Servlet就是组件
image.png
2.SpringMVC框架的优点
1)轻量级,基于MVC的框架
2)易于上手,容易理解,功能强大
3)它具备IOC和AOP
4)完全基于注解开发

时序图解析

image.png

SpringMVC执行流程

image.png

二、基于注解的SpringMVC框架开发的步骤

1)新建项目,选择webapp模板.

2)修改目录,添加缺失的test,java,resources(两套),并修改目录属性

image.png

3)修改pom.xml文件,添加SpringMVC的依赖,添加Servlet的依赖

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-webmvc</artifactId>
  4. <version>5.2.5.RELEASE</version>
  5. </dependency>
  6. <!--添加servlet的依赖-->
  7. <dependency>
  8. <groupId>javax.servlet</groupId>
  9. <artifactId>javax.servlet-api</artifactId>
  10. <version>3.1.0</version>
  11. </dependency>

4)添加springmvc.xml配置文件,指定包扫描,添加视图解析器.

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. 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">
  6. <!--添加包扫描-->
  7. <context:component-scan base-package="com.bjpowernode.controller"></context:component-scan>
  8. <!--添加视图解析器-->
  9. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  10. <!--配置前缀-->
  11. <property name="prefix" value="/admin/"></property>
  12. <!--配置后缀-->
  13. <property name="suffix" value=".jsp"></property>
  14. </bean>
  15. </beans>

5)删除web.xml文件,新建web.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  5. version="4.0">
  6. </web-app>

6)在web.xml文件中注册springMVC框架(所有的web请求都是基于servlet的)

分析web请求
web请求执行的流程
核心处理器
index.jsp<———————->DispatcherServlet<—————————->SpringMVC的处理器是一个普通的方法
one.jsp <———————->DispatcherServlet<—————————->SpringMVC的处理器是一个普通的方法

DispatcherServlet要在web.xml文件中注册才可用.

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  5. version="4.0">
  6. <!--注册SpringMVC框架-->
  7. <servlet>
  8. <servlet-name>springmvc</servlet-name>
  9. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  10. <init-param>
  11. <param-name>contextConfigLocation</param-name>
  12. <param-value>classpath:springmvc.xml</param-value>
  13. </init-param>
  14. </servlet>
  15. <servlet-mapping>
  16. <servlet-name>springmvc</servlet-name>
  17. <!--
  18. 指定拦截什么样的请求
  19. http://localhost:8080/one
  20. http://localhost:8080/index.jsp
  21. http://localhost:8080/demo.action
  22. <a href="${pageContext.request.contextPath}/demo.action">访问服务器</a>
  23. -->
  24. <url-pattern>*.action</url-pattern>
  25. </servlet-mapping>
  26. </web-app>

7)在webapp目录下新建admin目录,在admin目录下新建main.jsp页面,删除index.jsp页面,并新建,发送请求给服务器

image.png

  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: Administrator
  4. Date: 2022/2/28
  5. Time: 15:43
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  9. <html>
  10. <head>
  11. <title>Title</title>
  12. </head>
  13. <body>
  14. <h2>main...........</h2>
  15. </body>
  16. </html>
  1. <%--
  2. Created by IntelliJ IDEA.
  3. User: Administrator
  4. Date: 2022/2/28
  5. Time: 16:00
  6. To change this template use File | Settings | File Templates.
  7. --%>
  8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  9. <html>
  10. <head>
  11. <title>Title</title>
  12. </head>
  13. <body>
  14. <br><br><br>
  15. <a href="${pageContext.request.contextPath}/demo.action">访问服务器zar</a>
  16. </body>
  17. </html>

8)开发控制器(Servlet),它是一个普通的类.

  1. @Controller //交给Spring去创建对象
  2. public class DemoAction {
  3. /**
  4. * 以前的Servlet的规范
  5. * protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}
  6. * action中所有的功能实现都是由方法来完成的
  7. * action方法的规范
  8. * 1)访问权限是public
  9. * 2)方法的返回值任意
  10. * 3)方法名称任意
  11. * 4)方法可以没有参数,如果有可是任意类型
  12. * 5)要使用@RequestMapping注解来声明一个访问的路径(名称)
  13. *
  14. */
  15. @RequestMapping("/demo")
  16. public String demo(){
  17. System.out.println("zar服务器被访问到了.......");
  18. return "main"; //可以直接跳到/admin/main.jsp页面上
  19. }
  20. }

9)添加tomcat进行测试功能

1.@RequestMapping注解详解

此注解就是来映射服务器访问的路径.
1)此注解可加在方法上,是为此方法注册一个可以访问的名称(路径)

  1. @RequestMapping("/demo")
  2. public String demo(){
  3. System.out.println("服务器被访问到了.......");
  4. return "main"; //可以直接跳到/admin/main.jsp页面上
  5. }
  6. <a href="${pageContext.request.contextPath}/demo.action">访问服务器</a>

2)此注解可以加在类上,相当于是包名(虚拟路径),区分不同类中相同的action的名称

  1. @RequestMapping("/user")
  2. public class DemoAction1{
  3. @RequestMapping("/demo")
  4. public String demo(){
  5. System.out.println("user服务器被访问到了.......");
  6. return "main"; //可以直接跳到/admin/main.jsp页面上
  7. }
  8. }
  9. <a href="${pageContext.request.contextPath}/user/demo.action">访问服务器</a>

3)此注解可区分get请求和post请求

  1. @Controller
  2. public class ReqAction {
  3. @RequestMapping(value = "/req",method = RequestMethod.GET)
  4. public String req(){
  5. System.out.println("我是处理get请求的........");
  6. return "main";
  7. }
  8. @RequestMapping(value = "/req" ,method = RequestMethod.POST)
  9. public String req1(){
  10. System.out.println("我是处理post请求的........");
  11. return "main";
  12. }
  13. }
  14. <form action="${pageContext.request.contextPath}/req.action" method="post">
  15. <input type="submit" value="提交">
  16. </form><br><br><br>

三、 SpringMVC框架优化内容

我们需要优化的内容
image.png

1.五种数据提交方式的优化

1)单个提交数据

页面:

  1. <form action="${pageContext.request.contextPath}/one.action">
  2. 姓名:<input name="myname"><br>
  3. 年龄:<input name="age"><br>
  4. <input type="submit" value="提交">
  5. </form>

action:

  1. @RequestMapping("/one")
  2. public String one(String myname,int age){ //===>自动注入,并且类型转换
  3. System.out.println("myname="+myname+",age="+(age+100));
  4. return "main";
  5. }

2)对象封装提交数据

  1. 在提交请求中,保证请求参数的名称与实体类中成员变量的名称一致,则可以自动创建对象,则可以自动提交数据,自动类型转换,自动封装数据到对象中.<br /> 实体类:
  1. public class Users {
  2. private String name;
  3. private int age;
  4. }

页面:

  1. <form action="${pageContext.request.contextPath}/two.action" method="post">
  2. 姓名:<input name="name"><br>
  3. 年龄:<input name="age"><br>
  4. <input type="submit" value="提交">
  5. </form>

action:

  1. @RequestMapping("/two")
  2. public String two(Users u){
  3. System.out.println(u);
  4. return "main";
  5. }

3)动态占位符提交

  1. 仅限于超链接或地址拦提交数据.它是一杠一值,一杠一大括号,使用注解@PathVariable来解析.
  1. <a href="${pageContext.request.contextPath}/three/张三/22.action">动态提交</a>
  2. @RequestMapping("/three/{uname}/{uage}")
  3. public String three(
  4. @PathVariable("uname") //===>用来解析路径中的请求参数
  5. String name,
  6. @PathVariable("uage")
  7. int age){
  8. System.out.println("name="+name+",age="+(age+100));
  9. return "main";
  10. }

4)映射名称不一致

  1. 提交请求参数与action方法的形参的名称不一致,使用注解@RequestParam来解析
  1. /**
  2. * 姓名:<input name="name"><br>
  3. * 年龄:<input name="age"><br>
  4. */
  5. @RequestMapping("/four")
  6. public String four(
  7. @RequestParam("name") ===>专门用来解决名称不一致的问题
  8. String uname,
  9. @RequestParam("age")
  10. int uage){
  11. System.out.println("uname="+uname+",uage="+(uage+100));
  12. return "main";
  13. }

5)手工提取数据

  1. /**
  2. * 姓名:<input name="name"><br>
  3. * 年龄:<input name="age"><br>
  4. */
  5. @RequestMapping("/five")
  6. public String five(HttpServletRequest request){
  7. String name = request.getParameter("name");
  8. int age = Integer.parseInt(request.getParameter("age"));
  9. System.out.println("name="+name+",age="+(age+100));
  10. return "main";
  11. }

(添加)中文乱码解决方案

  1. 配置过滤器.
  2. <filter>
  3. <filter-name>encode</filter-name>
  4. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  5. <!--
  6. 配置参数
  7. private String encoding;
  8. private boolean forceRequestEncoding;
  9. private boolean forceResponseEncoding;
  10. -->
  11. <init-param>
  12. <param-name>encoding</param-name>
  13. <param-value>UTF-8</param-value>
  14. </init-param>
  15. <init-param>
  16. <param-name>forceRequestEncoding</param-name>
  17. <param-value>true</param-value>
  18. </init-param>
  19. <init-param>
  20. <param-name>forceResponseEncoding</param-name>
  21. <param-value>true</param-value>
  22. </init-param>
  23. </filter>
  24. <filter-mapping>
  25. <filter-name>encode</filter-name>
  26. <url-pattern>/*</url-pattern>
  27. </filter-mapping>

2.action方法的返回值

1)String:客户端资源的地址,自动拼接前缀和后缀.还可以屏蔽自动拼接字符串,可以指定返回的路径.

2)Object:返回json格式的对象.自动将对象或集合转为json.使用的jackson工具进行转换,必须要添加jackson依赖.一般用于ajax请求.

3)void:无返回值,一般用于ajax请求.

4)基本数据类型,用于ajax请求.

5)ModelAndView:返回数据和视图对象,现在用的很少

完成ajax请求访问服务器,返回学生集合.

1)添加jackson依赖

  1. <dependency>
  2. <groupId>com.fasterxml.jackson.core</groupId>
  3. <artifactId>jackson-databind</artifactId>
  4. <version>2.9.8</version>
  5. </dependency>

2)在webapp目录下新建js目录,添加jQuery函数库
3)在index.jsp页面上导入函数库

  1. function show() {
  2. $.ajax({
  3. url:"${pageContext.request.contextPath}/ajax.action",
  4. dataType:"json",
  5. type:"get",
  6. success:function (list) {
  7. // alert(list);
  8. var s="";
  9. $.each(list,function (i,stu) {
  10. // alert(stu);
  11. s+=stu.name+"----"+stu.age+"<br>";
  12. });
  13. $("#mydiv").html(s);
  14. }
  15. });
  16. }

4)在action上添加注解@ResponseBody,用来处理ajax请求

  1. @Controller
  2. public class AjaxAction {
  3. //处理ajax请求,一定要加@ResponseBody
  4. @ResponseBody
  5. @RequestMapping("/ajax")
  6. public List<Student> ajax(){
  7. Student stu1 = new Student("张三",22);
  8. Student stu2 = new Student("李四",24);
  9. Student stu3 = new Student("王五",23);
  10. List<Student> list = new ArrayList<>();
  11. list.add(stu1);
  12. list.add(stu2);
  13. list.add(stu3);
  14. //调用json转换工具ObjectMapper进行转换
  15. return list; //===>springmvc负责转换成json
  16. }
  17. }

5)在springmvc.xml文件中添加注解驱动,它用来解析@ResponseBody注解

  1. <mvc:annotation-driven></mvc:annotation-driven>

3.四种跳转方式

本质还是两种跳转:请求转发和重定向,衍生出四种是请求转发页面,转发action,重定向页面,重定向action
image.png
请求转发

  1. @RequestMapping("/one")
  2. public String one(){
  3. System.out.println("这是请求转发页面跳转.........");
  4. return "main"; //默认是请求转发,使用视图解析器拼接前缀后缀进行页面跳转
  5. }
  1. @RequestMapping("/two")
  2. public String two(){
  3. System.out.println("这是请求转发action跳转.........");
  4. // /admin/ /other.action .jsp
  5. //forward: 这组字符串可以屏蔽前缀和后缀的拼接.实现请求转发跳转
  6. return "forward:/other.action";
  7. }

重定向

  1. @RequestMapping("/three")
  2. public String three(){
  3. System.out.println("这是重定向页面.......");
  4. //redirect: 这组字符串可以屏蔽前缀和后缀的拼接.实现重定向跳转
  5. return "redirect:/admin/main.jsp";
  6. }
  1. @RequestMapping("/four")
  2. public String four(){
  3. System.out.println("这是重定向action.......");
  4. //redirect: 这组字符串可以屏蔽前缀和后缀的拼接.实现重定向跳转
  5. return "redirect:/other.action";
  6. }

//随便跳

  1. @RequestMapping("/five")
  2. public String five(){
  3. System.out.println("这是随便跳.......");
  4. return "forward:/fore/login.jsp";
  5. }

4.SpringMVC默认的参数类型

不需要去创建,直接拿来使用即可.
1)HttpServletRequest
2)HttpServletResponse
3)HttpSession
4)Model
5)Map
6)ModelMap

  1. @Controller
  2. public class DataAction {
  3. @RequestMapping("/data")
  4. public String data(HttpServletRequest request,
  5. HttpServletResponse response,
  6. HttpSession session,
  7. Model model,
  8. Map map,
  9. ModelMap modelMap){
  10. //做一个数据,传到main.jsp页面上
  11. Users u = new Users("张三",22);
  12. //传递数据
  13. request.setAttribute("requestUsers",u);
  14. session.setAttribute("sessionUsers",u);
  15. model.addAttribute("modelUsers",u);
  16. map.put("mapUsers",u);
  17. modelMap.addAttribute("modelMapUsers",u);
  18. return "main"; //请求转发方式跳转
  19. // return "redirect:/admin/main.jsp";
  20. }
  21. }

注意:Map,Model,ModelMap和request一样,都使用请求作用域进行数据传递.所以服务器端的跳转必须是请求转发.

5.日期处理

1)日期的提交处理
A.单个日期处理
要使用注解@DateTimeFormat,此注解必须搭配springmvc.xml文件中的

  1. @RequestMapping("/mydate")
  2. public String mydate(
  3. @DateTimeFormat(pattern = "yyyy-MM-dd")
  4. Date mydate){
  5. System.out.println(mydate);
  6. System.out.println(sf.format(mydate));
  7. return "show";
  8. }
  1. <!--添加注解驱动-->
  2. <!--<mvc:annotation-driven></mvc:annotation-driven>-->
  1. B.类中全局日期处理<br /> 注册一个注解,用来解析本类中所有的日期类型,自动转换.
  1. //注册一个全局的日期处理注解
  2. @InitBinder
  3. public void initBinder(WebDataBinder dataBinder){
  4. dataBinder.registerCustomEditor(Date.class,new CustomDateEditor(sf,true));
  5. }
  6. @RequestMapping("/mydate")
  7. public String mydate(Date mydate, HttpServletRequest request){
  8. System.out.println(mydate);
  9. System.out.println(sf.format(mydate));
  10. request.setAttribute("mydate",sf.format(mydate));
  11. return "show";
  12. }

2)日期的显示处理

  1. public class Student {
  2. private String name;
  3. @DateTimeFormat(pattern = "yyyy-MM-dd")
  4. private Date birthday; //String ????
  5. @Override
  6. public String toString() {
  7. return "Student{" +
  8. "name='" + name + '\'' +
  9. ", birthday=" + birthday +
  10. '}';
  11. }
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public Date getBirthday() {
  19. return birthday;
  20. }
  21. @DateTimeFormat(pattern = "yyyy-MM-dd")
  22. public void setBirthday(Date birthday) {
  23. this.birthday = birthday;
  24. }
  25. public Student(String name, Date birthday) {
  26. this.name = name;
  27. this.birthday = birthday;
  28. }
  29. public Student() {
  30. }
  31. }
  1. @RequestMapping("/list")
  2. public String list(HttpServletRequest request) throws ParseException {
  3. Student stu1 = new Student("张三",sf.parse("2000-01-01"));
  4. Student stu2 = new Student("李四",sf.parse("2001-08-11"));
  5. Student stu3 = new Student("王五",sf.parse("2002-09-21"));
  6. List<Student> list = new ArrayList<>();
  7. list.add(stu1);
  8. list.add(stu2);
  9. list.add(stu3);
  10. request.setAttribute("list",list);
  11. return "show";
  12. }

在页面上显示好看的日期,必须使用JSTL.
步骤:
A)添加依赖jstl

  1. <dependency>
  2. <groupId>jstl</groupId>
  3. <artifactId>jstl</artifactId>
  4. <version>1.2</version>
  5. </dependency

B)在页面上导入标签库
如果是单个日期对象,直接转为好看的格式化的字符串进行显示.
如果是list中的实体类对象的成员变量是日期类型,则必须使用jstl进行显示.

  1. <%--导入jstl核心标签库--%>
  2. <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  3. <%--导入jstl格式化标签库--%>
  4. <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

C)使用标签显示数据

  1. <table width="800px" border="1">
  2. <tr>
  3. <th>姓名</th>
  4. <th>生日</th>
  5. </tr>
  6. <c:forEach items="${list}" var="stu">
  7. <tr>
  8. <td>${stu.name}</td>
  9. <td>${stu.birthday}------ <fmt:formatDate value="${stu.birthday}" pattern="yyyy-MM-dd"></fmt:formatDate></td>
  10. </tr>
  11. </c:forEach>
  12. </table>

6.SpringMVC的拦截器

针对请求和响应进行的额外的处理.在请求和响应的过程中添加预处理,后处理和最终处理.
image.png
拦截器执行的时机
1)preHandle():在请求被处理之前进行操作,预处理
2)postHandle():在请求被处理之后,但结果还没有渲染前进行操作,可以改变响应结果,后处理
3)afterCompletion:所有的请求响应结束后执行善后工作,清理对象,关闭资源 ,最终处理.
拦截器实现的两种方式
1)继承HandlerInterceptorAdapter的父类
2)实现HandlerInterceptor接口,实现的接口,推荐使用实现接口的方式
拦截器实现的步骤
1)改造登录方法,在session中存储用户信息,用于进行权限验证

  1. @RequestMapping("/login")
  2. public String login(String name, String pwd, HttpServletRequest request){
  3. if("zar".equalsIgnoreCase(name) && "123".equalsIgnoreCase(pwd)){
  4. //在session中存储用户信息,用于进行权限验证
  5. request.getSession().setAttribute("users",name);
  6. return "main";
  7. }else{
  8. request.setAttribute("msg","用户名或密码不正确!");
  9. return "login";
  10. }
  11. }

2)开发拦截器的功能.实现HandlerInterceptor接口,重写preHandle()方法

  1. if(request.getSession().getAttribute("users") == null){
  2. //此时就是没有登录,打回到登录页面,并给出提示
  3. request.setAttribute("msg","您还没有登录,请先去登录!");
  4. request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
  5. return false;
  6. }
  7. return true;//放行请求

3)在springmvc.xml文件中注册拦截器

  1. <mvc:interceptors>
  2. <mvc:interceptor>
  3. <!--映射要拦截的请求-->
  4. <mvc:mapping path="/**"/>
  5. <!--设置放行的请求-->
  6. <mvc:exclude-mapping path="/showLogin"></mvc:exclude-mapping>
  7. <mvc:exclude-mapping path="/login"></mvc:exclude-mapping>
  8. <!--配置具体的拦截器实现功能的类-->
  9. <bean class="com.bjpowernode.interceptor.LoginInterceptor"></bean>
  10. </mvc:interceptor>
  11. </mvc:interceptors>