0、三阶段的内容:

SSM框架—SpringMVC + Spring + MyBatis + Redis + Nginx
做一个项目
SpringBoot + Vue 也要做一个项目

一、三层架构+MVC模型

三层架构:
表现层:web层,不是说页面的,而是和页面打交道的java层(Servlet,SpringMVC)
Servlet —> SpringMVC Struts2
业务层:提供服务的层面 Service层 —>Spring
持久层: 关于数据的层面 Dao层(MySQL + Redis。。。)
太多的框架—>jdbc,jdbcTemplate,Mybatis,JPA,Hibernate。。。。。
MVC模型:—SpringMVC
M: Model 数据模型 —> POJO
V:View 视图 jsp,html
C: Controller 控制层(Servlet)

二、SpringMVC的概念

SpringMVC是由Spring基金组织开发的,符合MVC模型的这样一种表现层的框架。它是基于Servlet实现的。工作职责就是替代servlet,完成页面上的数据到java代码,java代码的数据传递给页面,还可以进行界面的跳转。
它和Struts2一样都是一个web层框架,Struts2是一个基于filter实现的web框架。

三、SpringMVC入门案例

1、创建一个maven的web项目,导入jar包
image.png
image.png
image.png
image.pngimage.png
image.png
image.png
新建完项目之后,导入jar包
如果遇到导入包之后没啥反应的,可以如下操作
image.png

  1. <!--一定要编写打包方式,否则,项目启动之后无法访问-->
  2. <packaging>war</packaging>
  3. <!--定义各个jar包的版本号,后面统一通过${} 的方式引用该版本号-->
  4. <properties>
  5. <spring.version>5.0.2.RELEASE</spring.version>
  6. </properties>
  7. <dependencies>
  8. <dependency>
  9. <groupId>org.springframework</groupId>
  10. <artifactId>spring-context</artifactId>
  11. <version>${spring.version}</version>
  12. </dependency>
  13. <dependency>
  14. <groupId>org.springframework</groupId>
  15. <artifactId>spring-web</artifactId>
  16. <version>${spring.version}</version>
  17. </dependency>
  18. <dependency>
  19. <groupId>org.springframework</groupId>
  20. <artifactId>spring-webmvc</artifactId>
  21. <version>${spring.version}</version>
  22. </dependency>
  23. </dependencies>

2、编写代码—Controller

@Controller //编写一个注解,用于表示该类是一个Controller类
public class HelloController {

    @RequestMapping("/hello")
    public String sayHello(){
        System.out.println("这是我的第一个Controller");
        return "success.jsp";//此处需要写跳转页面的路径
    }
}

3、编写一个页面
在webapp文件夹下,编写了一个success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
  跳转到该页面,表示你的代码已经成功了!
</body>
</html>

3、编写springmvc.xml 这个是必须写的,将来所有的springmvc的配置都编写在该xml中。在resources文件夹下创建

<?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">

    <!--扫描你的所有关于@Controller的注解的类-->
    <context:component-scan base-package="com.qfedu.controller"/>
    <!--开启注解-->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

4、配置前端控制器(总开关,大脑,BOSS)—在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>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.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>
</web-app>

遇到的问题:
当你编写的项目,编译完之后出现了 out target两个编译完之后的文件夹,要警惕
image.png
出现了部署上的问题
解决方案:
1、使用tomcat插件(不建议大家用)
2、检查部署上有啥问题
image.png
http://localhost/虚拟路径名/hello
image.png

四、原理分析

1)加载顺序的原理:

1、tomcat一启动,加载web.xml,dispatcherServlet就会被加载,因为<load-on-startup>1</load-on-startup>
加载的时候创建dispathcherServlet,创建的时候加载了
image.png
2、该配置文件一加载,就去扫描com.qfedu.controller下的所有带有@Controller的注解的类
image.png
3、带有@Controller的注解都被spring容器,给加载到了jvm内存中,并且帮我们创建好了Controller的实例化对象,等着以后使用即可。

2)执行原理

image.png
面试重点:springmvc运行原理图 (戏称 一个中心DispatcherServlet三个基本点【处理器映射器,处理器适配器,视图解析器】)
1、浏览器发送请求 /hello 给前端控制器DispatcherServlet ,这个是一个大脑,控制所有其他组件的运行
2、前端控制器去问处理器映射器(编写了一堆某个url对应某个类中的哪个方法),处理器映射器告诉前端控制器,哪个类中的哪个方法可以处理
3、前端控制器去找处理器适配器,告诉它执行哪个类中的哪个方法,处理器适配器接到命令之后,就去执行处理器(Handler),其实就是一个方法,也就是说一个方法就是一个处理器。处理器执行完方法之后,将一个ModelAndView对象给处理器适配器,处理器适配器上交处理结果—ModelAndView(数据+页面)
4、前端控制器拿着ModelAndView 对象传递给视图解析器,让其解析,解析的结果传递给前端控制器
5、前端控制器拿到渲染之后的页面,传递给浏览器。
关注点:前端控制器,处理器映射器,处理器适配器,视图解析器,都不需要我们来管,自动运行的,我们开发人员只需要关注处理器如何编写,页面如何编写即可。

拓展:
关于web-inf下的资源,是无法通过浏览器直接访问到的。资源存放在这个文件夹下面,是非常安全的。但是我们如何访问到它呢?
我们通过视图解析器访问到该资源。

@RequestMapping("/a")
    public String sayA(){
        System.out.println("此处访问一个隐蔽的资源");
        return "WEB-INF/page/a.jsp";
    }

以上方案解决了安全性问题,也访问到了我们想要的资源,但是每次路径很重复。我们可以通过配置视图解析器的方式来解决。

<!--配置视图解析器解决访问路径过长的问题-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/page/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

classpath : 类路径, 编译完之后的classes文件夹
image.png

五、参数的传递(绑定)

springmvc —> 1、将页面的数据传递给controller
2、将java代码(Controller)中的数据,传递给页面
3、跳转页面
支持的数据类型:

1、基本数据类型和字符串类型

    [http://localhost/SpringMVC_01/edit?id=10&name=zhangsan](http://localhost/SpringMVC_01/edit?id=10&name=zhangsan)      模拟的是get请求,post请求也是一样的,只需要表单中的参数名字和方法中的参数名字一样就可以了<br />     我们只需要保证请求的参数名字和方法的变量的名字一样,就可以直接赋值
@RequestMapping("/edit")
    public String getParams01(int id,String name){

        System.out.println(id);
        System.out.println(name);
        return "a";
    }

2、实体类型

<form action="${pageContext.request.contextPath}/save" method="post">
    姓名: <input name="name" type="text"/><br/>
    手机号: <input name="phone" type="text"/><br/>
    身份证号: <input name="cardNum" type="text"/><br/>
    <input type="submit" value="提交"/>
</form>
public class User {
    private String name;
    private String phone;
    private String cardNum;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getCardNum() {
        return cardNum;
    }

    public void setCardNum(String cardNum) {
        this.cardNum = cardNum;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", phone='" + phone + '\'' +
                ", cardNum='" + cardNum + '\'' +
                '}';
    }
}
    @RequestMapping("/save")
    public String save(User user){
        System.out.println(user);
        return "a";
    }

一定要注意:页面中的表单中的name值,一定要和实体中的属性名称保持一致,否则,数据无法传递。
实体中的属性指的是什么?getName-> Name —>name 这个才是属性,而不是类中的变量名。

3、集合类型(list\map类型)— 不常用

解决中文乱码问题—提交数据的时候的中文乱码 web.xml

<!--解决页面上的数据到controller中,中文乱码问题-->
    <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>

六、常用的注解

1、RequestMapping 请求映射

   1)ElementType.**_METHOD_**, ElementType.**_TYPE  说明该注解可以使用在方法和类上。_**<br />**_       2)path   value  两者是一会儿事儿   都可以存放数组    _**@RequestMapping(path={**"/demo01"**,**"/demo02"**})<br />               [http://localhost/SpringMVC_01/user/demo02](http://localhost/SpringMVC_01/user/demo02)    <br />       3)method   限定某个url中的方法,必须是某一种类型,比如我指定是post请求方式,get方式就不可以   RequestMethod<br />                 method = RequestMethod.**_GET_**

2、RequestParam

    问题: http://localhost/xxxxx/save?id=10&name=zhangsan<br />       public String  show(int id,String username){<br />        }<br />     解决请求参数和方法中的参数名字不一致的问题。<br />   1、 一般作用于参数前面,可以指定url中的名称和参数名称的一个对应关系   username-->name  <br />   2、可以指定某些参数是否为必须的。默认都是必须的<br />   3、可以指定某些参数的一个默认值,当前端页面没有传递该值时,可以使用指定的默认值。<br />代码演示:
//http://localhost/SpringMVC_01/user/demo03?username=zhangsan
    @RequestMapping("/demo03")
    public String b(@RequestParam(value ="username",required = true,defaultValue = "老闫") String name) {

        System.out.println(name);
        return "a";
    }

3、PathVariable 注解 — 可以通过该注解实现restful风格的请求

         http://localhost:8080/xxxxx/save?id=1&name=zhangsan&age=10<br />      restful风格的请求:[http://localhost/SpringMVC_01/user/edit/1/zhangsan/10](http://localhost/SpringMVC_01/user/edit/1/zhangsan/10)<br />      restful风格的请求:结构清晰,易于理解,拓展方便,非常流行
//http://localhost:8080/xxxxx/edit/1/zhangsan/10
    @RequestMapping("/edit/{id}/{name}/{age}")
    public String c(@PathVariable(value="id")int sid,@PathVariable(value="name") String sName,@PathVariable(value="age") int age){
        System.out.println(sid);
        System.out.println(sName);
        System.out.println(age);
        return "a";
    }

七、补充—数据类型转换器

   页面上有个生日:birthday       User 实体中  Date birthday<br />      页面上的是String    -- >  Date<br /> 1、 需要先写一个数据类型转换器:
public class StringToDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
        if(source == null || source.equals("")){
            return null;
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = simpleDateFormat.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

2、配置转换器 一定要记得,在注解驱动里面配置一下

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.qfedu.converter.StringToDateConverter"/>
            </set>
        </property>
    </bean>


    <!--开启注解-->
    <!--<mvc:annotation-driven></mvc:annotation-driven>-->
    <mvc:annotation-driven conversion-service="conversionService"/>

至此,我们提交表单数据时,遇到实体中有Date类型就能正常解析了。