【spring mvc】Spring mvc 介绍

1、MVC介绍和控制层演示

MVC是模型(Model) 视图(View)和控制器(Controller)

模型:业务逻辑和保存数据的状态,其实落地就是 dao、service。
视图:显示界面,就是 jsp
控制器:取数据,调用业务逻辑,转向指定的界面,就是基于 Servlet。

首先记录一个简单的例子(没有具体的业务层):

1.1、创建普通的Maven项目,导入依赖

<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
    </dependency>
</dependencies>

1.2、创建servlet,逻辑就是获取请求名,然后创建msg参数,重定向显示到指定界面

package com.wcy.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取前端参数
        String method = req.getParameter("method");
        if (method.equals("add")) {
            req.getSession().setAttribute("msg","执行了add方法");
        }
        if (method.equals("delete")) {
            req.getSession().setAttribute("msg","执行了delete方法");
        }
        //2.调用业务层


        //3.视图转发或者重定向
        req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);
    }


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

1.3、创建web,这里老师用的是这样的方式创建web支持

编写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">
    <!--编写对应请求的servlet对应的类-->
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.wcy.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--对应请求名和method名-->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

1.4、编写test.jsp视图显示servlet处理的结果

</head>
<body>
${msg}
</body>
</html>

1.5、结果

2 SpringMVC原理

2.1、简介

Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从一开始就包含在 Spring Framework 中

官方文档:

https://docs.spring.io/spring-framework/docs/current/reference/html/web.html

2.2、DispatcherServlet

官网原话:Spring MVC 与许多其他 Web 框架一样,是围绕前端控制器模式设计的,其中一个中央控制器Servlet为DispatcherServlet请求处理提供共享算法,而实际工作由可配置的委托组件执行。该模型非常灵活,支持多种工作流程。

下图是DispatcherServlet的继承关系

2.3、实例

官网的图(中文版)

实际DispatcherServlet底层调用关系:实现部分为框架实现的,虚线部分用户自定义。

发起Http请求

HandleMapping为处理器映射,DispatcherServlet调用HandleMapping,HandleMapping根据请求url查找Handle
HandleExcution表示具体的Handle,其主要作用是根据url查找控制器,例子中url被查找控制器为:hello
HandleExcution将解析后的信息交给DispatcherServlet,如解析控制器映射等
HandleAdapter表示处理器适配器,其按照特定的规则去实现Handle
HandleAdapter让具体的Controller执行
Controller将具体的执行信息返回给HandleAdapter,如ModelAndView。
HandleAdapter将逻辑视图名或模型传递给DispatcherServlet
DispatcherServlet调用视图解析器(ViewResolver)来解析DispatcherServlet传递的逻辑视图名
视图解析器将解析的传递给DispatcherServlet
DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图
最终视图呈现给用户

对照这个底层原理,来看代码:

  • 首先进入首页,然后发送http请求

  • 然后进入到web.xml,这里注册了DispatcherServlet以及绑定了需要处理的请求,hello就在其中
<?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">


    <!--注册servlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <!--启动级别1-->
        <load-on-startup>1</load-on-startup>
    </servlet>


    <!--匹配所有请求(不包括jsp)-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  • DispatcherServlet,根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括一个Handler处理器对象、多个HandlerInterceptor拦截器对象),最后以HandlerExecutionChain对象的形式返回。
<--springmvc-servlet.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--处理器映射和处理器声明-->
    <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>


    <!--Handle-->
    <bean id="/hello" class="com.wcy.controller.HelloController"/>
</beans>
  • DispatcherServlet将解析度控制器信息交给HandleAdapter,HandleAdapter让具体的Controller执行,就是下面这个。
package com.wcy.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class HelloController implements Controller {
    public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        //ModelAndView模型和视图
        ModelAndView mv = new ModelAndView();
        //封装对象,放到ModelAndView中
        mv.addObject("msg","HelloSpringMVC!");
        //封装要跳转的视图,放到ModelAndView里
        mv.setViewName("hello");
        return mv;
    }
}
  • 执行完毕之后将ModelAndView信息返回给HandleAdapter,HandleAdapter返回给DispatcherServlet

  • DispatcherServlet调用ViewResolver来解析逻辑视图名

<!--视图解析器: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>
  • 解析完毕了,发现是给hello.jsp(/WEB-INF/jsp/hello.jsp)渲染图片。

3、SpringMVC-注解实现

3.1、介绍

对比与用继承Controller,然后springmvc-servlet里声明处理器映射和处理器声明,注解非常的方便,也是开发日常真正用的。

3.2、示例

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


    <!--注册servlet-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc-servlet.xml</param-value>
        </init-param>
        <!--启动级别1-->
        <load-on-startup>1</load-on-startup>
    </servlet>


    <!--匹配所有请求(不包括jsp)-->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern> 
    </servlet-mapping>
</web-app>

注意springmvc-servlet.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">


    <!--自动扫描包,让指定包下的注解生效,由IOC容器统一管理-->
    <context:component-scan base-package="com.wcy.controller"/>
    <!--让springMVC不处理静态资源,css,js什么的-->
    <mvc:default-servlet-handler/>
    <!--支持mvc注解驱动-->
    <mvc:annotation-driven/>


    <!--视图解析器: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>
</beans>

控制器,控制器通过@Controller标注为控制器,@RequestMapping标注请求名,

package com.wcy.controller;


import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@Controller(被这个注解标注的类,会被spring接管,这个类中给所有方法如果返回值为string,并且具体页面可以跳转,那么就会被视图解析器解析)
@RequestMapping("/HelloController")
//@RestController(如果是这个注解,返回值就是json字符串了)
public class HelloController {


    //localhost:8080/HelloController/hello
    @RequestMapping("/hello")
    public String hello(Model model) {
        //封装数据
        model.addAttribute("msg","hello springMVC annotation");
        return "hello";
    }

    //这里的redirect是重定向的意思,重定向就是说地址会变,例如这里 //localhost:8080/HelloController/hello 会变成//localhost:8080/index

    @RequestMapping("/hello2")
    public String hello(Model model) {
        //封装数据
        model.addAttribute("msg","hello springMVC annotation");
        return "redirect:index";
    }
}

4、SpringMVC-接受请求和数据显示

4.1、Controller

核心就两个,一个 @GetMapping()标签,一个@PostMapping()标签,这两个分别对应get请求和post请求。

然后就是@RequestParam("name"),默认参数名一样能对应上,建议都写@RequestParam("name")绑定参数名字,规范也易区分后端的参数

package com.wcy.controller;


import com.wcy.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;


@Controller
@RequestMapping("/user")
public class UserController {
    //localhost:8080/user/t1?name=wcy
    @GetMapping("/t1")
    public String test(@RequestParam("name") String name, Model model) {
        System.out.println("接受到的前端参数信息为:" + name);
        model.addAttribute("name",name);
        return "test";
    }


    //localhost:8080/user/t2?id=1&age=24&name=wcy
    @GetMapping("/t2")
    public String test2(User user, Model model) {
        System.out.println("接受到的前端参数信息为:" + user);
        model.addAttribute("name",user);
        return "test";
    }


    //ModelMap继承了LinkedHashMap,拥有LinkedHashMap的所有功能
    @GetMapping("/t3")
    public String test3(ModelMap map) {
     
        return "test";
    }

    @PostMapping("/e/t1")
    public String test1(String name, Model model) {
        System.out.println(name);
        model.addAttribute("name",name);
        return "test";
    }
}

4.2、前端显示

如这张图片,@ResponseBody注解会直接返回一个字符串,不走视图解析器

导入jackson的包

com.fasterxml.jackson.core jackson-databind 2.9.0

@RestController注解和@Controller不同就在于下面所有的方法都只会返回字符串

应用场景:日期格式

@RestController
public class testController {
    @RequestMapping("/t1")
    public String test() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        Date date = new Date();
        //自定义日期格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return mapper.writeValueAsString(sdf.format(date));
    }
}

4.3、SpringMVC乱码问题

  • 过滤器解决输入进来的数据

首先是加过滤器:这个过滤器是Spring框架帮我们写好的,但是对get的方法似乎支持不太好,有时候还有乱码就是需要找网上大神写的一些过滤器

<!--绑定过滤器,让所有的请求走过滤器-->
<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><!--这里有个坑,就是/*才能包括得了jsp,因为加了jsp过滤器 -->
</filter-mapping>

tomcat编码格式配置

 <Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000" redirectPort="8443" URIEncoding="utf-8"/> (标黑的是加上的)

自己写的一个过滤器

package com.wcy.filter;

import javax.servlet.*;
import java.io.IOException;

/*
这是自己写的过滤器,会发现只能过滤get请求,springMVC帮忙写了强大的过滤器
*/
public class EncodingFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("UTF-8");
        servletResponse.setCharacterEncoding("UTF-8");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    public void destroy() {

    }
}
  • json前端显示乱码解决
<!--解决json 乱码配置-->
    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
               <constructor-arg value="UTF-8"/>
            </bean>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                        <property name="failOnEmptyBeans" value="false"/>
                    </bean>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
posted @ 2023-02-28 11:24  吴承勇  阅读(15)  评论(0编辑  收藏  举报