SpringMVC学习(具体实现+底层原理)

Posted 滑稽404#

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringMVC学习(具体实现+底层原理)相关的知识,希望对你有一定的参考价值。

引人:MVC架构:

  • M:model(数据层)
  • V:view(视图层)
  • C:Controller 数据层和视图层通过控制层(接口)互相调用

一、依赖

spring-web和spring-webmvc里的web有点不一样,所以mvc必须导spring-webmvc
通过properties控制版本,方便改版本

	 <properties>
        <spring-version>5.3.6</spring-version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring-version}</version>
        </dependency>


        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring-version}</version>
        </dependency>

        <!--切面-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.13</version>
        </dependency>
    </dependencies>

二、具体配置(原理实现)

狂神说链接

1、具体实现流程

在这里插入图片描述

  1. 所有请求经过DispatcherServlet,交给他去调度
  2. 通过处理器映射器通过请求与Controller组件的映射关系(Bean或者Controller组件注解)定位到具体Controller
  3. 返回到前端控制器,然后前端控制器通过处理器适配器找到Controller
  4. Controller去调用业务层返回ModelAndView
  5. ModelAndView通过前端控制器交给视图解析器解析
  6. 通过解析返回相应的视图

2、web.xml配置前端控制器

 <!--配置前端控制器-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--绑定mvc配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <!--优先级-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!--所有请求都要经过前端控制器-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

3、配置mvc

	<!--处理器映射器-->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <!--处理器适配器-->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>


    <!--视图解析器:DispatcherServlet给他的ModelAndView-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>
	<!--注册controller-->
    <bean id="/hello" class="com.chime.controller.HelloController"/>

4、Controller

public class HelloController implements Controller{
    @Override
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        ModelAndView mv=new ModelAndView();
        //业务代码
        String result="Hello MVC";

        mv.addObject("msg",result);
        mv.setViewName("hello");

        return mv;
    }
}

5、404异常

  1. Artifacts没有lib库,需要手动添加
  2. 视图解析器前缀后缀错误

三、mvc注解实现

1、web.xml配置前端控制器

  <!--注册前端控制器-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--绑定配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--所有请求经过springmvc-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

2、配置mvc

开启注解扫描需要添加context命名空间
注册mvc需要添加mvc命名空间

	 <!--开启注解扫描-->
    <context:component-scan base-package="com.chime"/>
    <!--通过前缀注册mvc注解,自动生成HandlerMapping和HandlerAdapter-->
    <mvc:annotation-driven/>
    <!--过滤静态资源-->
    <mvc:default-servlet-handler/>

    <!--注册视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
annotation-driven用于注册注解驱动。

一般根据前缀来注册相关的注解类
<tx:annotation-driven/>:支持事务注解的(@Transactional)
<mvc:annotation-driven/>:支持MVC注解

3、Controller

@Controller
public class HelloController {
	//映射地址
    @RequestMapping("/hello")
    public String hello(Model model){
//        封装数据
        model.addAttribute("msg","Hello");
        return "hello";//交给视图解析器解析

    }
}

4、使用bean注册Controller的缺点

实现Controller的类只有一个实现方法,需要一个个配(一个Bean对应一个类)
而使用Controller注解,可以写多个方法,加上Mapping来映射

四、Restful风格

1、Restful和传统传参的区别

localhost:8080/login?username=qwe&password=123
localhost:8080/login/qwe/123
localhost:8080/add?a=3&b=4
localhost:8080/add/3/4

url的Restful风格传参,需要使用@PathVariable注解声明路径变量

	@RequestMapping("/add/{a}/{b}")
    public String test1(@PathVariable int a,@PathVariable String b, Model model){
        String result=a+b;
        model.addAttribute("msg","test1"+result);
        return "hello";
    }

2、Restful风格的优点

  1. 参数名称不会直接暴露在地址栏中
  2. 简洁高效

3、相同url怎么控制冲突

相同的url可以通过更改请求类型来访问,get请求只能访问Get,post请求只能访问post

  1. 使用RequestMapping的method参数设置请求类型
  2. 直接使用相应类型的Mapping
@RequestMapping(value= "/add/{a}/{b}",method = RequestMethod.GET)
@GetMapping("/add/{a}/{b}")
	//@RequestMapping(value= "/add/{a}/{b}",method = RequestMethod.GET)
    @GetMapping("/add/{a}/{b}")
    public String test1(@PathVariable int a,@PathVariable String b, Model model){
        String result=a+b;
        model.addAttribute("msg","test1"+result);
        return "hello";
    }

    //@RequestMapping(value= "/add/{a}/{b}",method = RequestMethod.POST)
    @PostMapping("/add/{a}/{b}")
    public String test2(@PathVariable int a,@PathVariable String b, Model model){
        String result=a+b;
        model.addAttribute("msg","test2 "+result);
        return "hello";
    }

五、转发和重定向

1、有视图解析器

  1. 视图解析器默认转发
  2. 转发写出forword后,就不会拼接了,需要直接写完整
  3. 重定向需要写出完整地址,而且WEB-INF访问不到,不能重定向进去
WEB-INF是WEB应用的安全目录,只允许服务端访问,不允许客户端访问(只能转发,不能重定向)
重定向就是服务端确定url后,将url交给客户端,客户端再直接访问,所有不能重定向到WEB-INF
  1. 携带数据用转发,重定向如果需要携带数据需要特殊jar包
 	@RequestMapping("/test3")
    public String test3(Model model){
        model.addAttribute("msg","转发");
        //return "forward:hello.jsp";
        return "hello";
    }

    @RequestMapping("/test4")
    public String test4(Model model){
        model.addAttribute("msg","重定向");
        return "redirect:/test.jsp";
    }

2、不用视图解析器

  1. 转发和重定向都要写出地址
  2. 转发可以访问WEB-INF
	 @RequestMapping("/test3")
    public String test3(Model model){
        model.addAttribute("msg","转发");
        return "forward:/WEB-INF/jsp/hello.jsp";
    }

    @RequestMapping("/test4")
    public String test4(Model model){
        model.addAttribute("msg","重定向");
        return "redirect:/index.jsp";
    }

六、Controller方法参数

1、普通类型参数

可以使用@RequestParam设置参数别名
localhost:8080/test5?username=qwe 
qwe就被name接收了
 	@RequestMapping("/test5")
    public String test5(@RequestParam("username") String name,Model model){
        model.addAttribute("username",name);
        return "hello";
    }

2、对象参数

前端根据参数名自动匹配对象的属性
http://localhost:8080/anno/test6?id=5&sex=男
没有name字段,则person对象的name属性为空
    @RequestMapping("/test6")
    public String test6(Person person, Model model){
        System.out.println(person);
        return "hello";
    }

七、前台乱码

web.xml里注册格式过滤器

	<!--字符格式过滤器-->
    <filter>
        <filter-name>encoding</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>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

乱码详细配置链接(狂神)

八、Json

1、前端

  <script>
        var user={
            id : "101",
            name: "张三",
            sex : "男"
        };
        console.log("对象:"+user);//会输出Object,不能显示属性
        console.log(user);

        var json = JSON.stringify(user);
        console.log("Json:"+json);

        var obj = JSON.parse(json);
        console.log("Obj:"+obj);
        console.log(obj);
    </script>

在这里插入图片描述

  1. Json是个有多个键值对的字符串
  2. 输出对象不能拼接字符串,如果拼接字符串会显示Object

2、后端

  1. @RestController:在Controller上声明,类中所有方法不会返回页面,只会返回值

  2. @ResponseBody:在Controller方法上上面,该方法不会返回页面,只会返回值

一般使用obj.toString()或者json转换包来返回json数据

  	@RequestMapping("json1")
//    @ResponseBody
    public String json1(以上是关于SpringMVC学习(具体实现+底层原理)的主要内容,如果未能解决你的问题,请参考以下文章

深入底层,仿SpringMVC自己写框架

学习笔记——SpringMVC处理响应数据;SpringMVC处理请求域响应乱码问题

多线程的底层原理是怎么样的?

java spring的底层机制和原理是啥?

SpringMVC请求处理流程Spring AOP原理--推荐阅读

OpenGL原理学习笔记