SpringMVC笔记

实现步骤

springmvc就是一个spring,直接像spring一样用就好了
spring通过IOC管理对象,可以通过bean标签,annotation
springmvc强化了注解annotation的使用

我们要做的是使用@controller创建控制器对象,吧对象放入到springmvc容器中,把创建的对象作为控制器使用,这个控制器可以处理用户请求,就像servlet一样,但他并不是servlet, 通过@controller创建的类是个普通类
一般一个请求的流程是:前端页面发送请求— 给servlet---- 再将请求交给我们的service、dao等

而springmvc是这样子:
他有一个servlet类:DispatcherServlet
前端发送请求— 给我们的DispatcherServlet---- 再将请求交给我们的controller

  • 新建web模板
  • 加入依赖
    • spring-webmvc依赖, 简介把spring的依赖都加入到项目
    • jsp, servlet 依赖
  • 在web.xml中注册springmvc的核心对象DispatcherServlet
  • 创建前端页面
  • 创建控制器类
    • 添加@Controller注解,并放入到springmvc容器中
    • 在类方法中添加@RequestMapping注解
  • 创建springmvc的配置文件
    • 声明组件扫描器,指定@controller所在的package
    • 声明视图解析器

依赖

我们首先添加依赖:

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>

servlet

然后我们在web.xml中注册DispatcherServlet

    <servlet>
        <servlet-name>myconf</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:webconfig.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

这里通过load-on-startup标签,确定了这个servlet会被加载
DispatcherServlet被加载的时候会执行init方法:

// 创建容器,读取配置文件
WebApplicationContext ctx = new WebApplicationContext("${contextConfigLocation}")
// 把容器对象放到servletcontext中
getServletContext.setAttribute(key, ctx)

servlet mapping:

    <servlet-mapping>
        <servlet-name>myconf</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

表示所有的.do结尾的请求都交给myconf这个servlet处理

servlet-mapping

关于servlet-mapping:我们有两种方式:
一种就是如上使用*.do这个
还有一种是使用/
关于URL,我们的URL可以由我们指定,而我们没有指定的,会交给Tomcat自带的servlet处理:

<!-- tomcat/conf/web.xml -->
    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- The mappings for the JSP servlet -->
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>

默认servlet-mapping冲突

当我们使用/来作为url-pattern的时候,显然和默认的url-pattern是冲突的,那么默认的就会失效,就不能访问静态资源。
那么我们这时候有两种方法解决这个问题:

第一种方法

我们在contextConfig文件中添加<mvc:default-servlet-handler/>标签
原理呢是这个标签会自动为我们添加DefaultServletHttpRequestHandler类,就是类会使用RequestDispatcher这个类的forward方法将请求转发给Tomcat处理

单独添加这个<mvc:default-servlet-handler/>标签是会有问题的:他将所有的/请求都转发给了默认handler,我们自己写的就不会使用了
所以我们要再添加个标签<mvc:annotation-driven/>来激活我们的注解
这个<mvc:annotation-driven/>标签还有别的作用,就是我们使用@ResponseBody注解,也就是想要返回json数据的时候,要添加这个标签才能处理我们自定义的数据,否则就只有内置的类String等可以被转换为json

第二种方法(主要)

使用<mvc:resources mapping="static/**" location="/static/"/>标签,其中mapping是静态资源的URI,location是静态资源所在的位置

配置文件

我们创建好servlet后,还要在配置文件中设置:

    <context:component-scan base-package="conf"/>

这就是个spring配置文件,我们在servlet标签中配置的contextConfigLocation属性所指向的配置文件
component-scan标签表示从base-package这个包里面去找组件。
我们可以用xml或annotation来创建组件

接下来我们创建controller:

//在类上方添加
@Controller
public class myController {

	// 在方法上添加
    @RequestMapping(value = "ww.do")
    public ModelAndView doSome(){
        System.out.println("it is doing!@#$!%!^!^");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg","wbwb");
        modelAndView.setViewName("sm.jsp");
        return modelAndView;
    }
}

表示ww.do这个路径,交给这个controller处理
返回一个ModelAndView对象,指向了sm.jsp这个前端页面

整理一下一个请求的过程

发送请求 some.do
Tomcat接收到请求,到web.xml文件中去找
找到了url-pattern,根据url-pattern找到了servlet标签,是一个dispatcherservlet
这个servlet对应的配置文件是webconfig.xml
这个webconfig.xml声明了组件在conf这个package中
conf这个package中找到了所有的controller
这些controller中的resultmapping中有找到了some.do对应的方法
所有就调用这个方法

在根据源码看一下过程

1、Tomcat启动,创建容器的过程:
通过load-on-startup来确定顺序,创建dispatcherservlet对象
这个dispatcherservlet是继承自各个servlet的,一层一层来说,启动是会调用init方法
这个init方法调用了initservletbean方法
这个initservletbean方法又调用了initWebApplicationContext方法来创建容器

2、处理请求的过程:
要知道这个我们先在浏览器disable cache然后再试
会先执行service方法
这个service方法,执行processRequest方法
这个processRequest方法,调用doService方法
这个doService方法,调用doDispatch方法
这个doDispatch方法,调用processDispatchResult方法

视图view

改变视图路径

由于view文件如果直接放在外面会被直接访问到
我们把他放到WEB-INF目录下,这个目录下的文件受到保护,不能直接通过网址输入访问到
我们可以在配置文件中设置view文件的路径:

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

然后在modelAndView.setViewName()的时候只需要填写prefixsuffix中间的就行了

这个@ResultMapping也可以在类上面添加,这样子就会在类里面的方法路径前面添加一个路径了:

@Controller
@RequestMapping("/test")
public class myController {

    @RequestMapping(value = "/ww.do")
    public ModelAndView doSome(){
        System.out.println("it is doing!@#$!%!^!^");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg","wbwb");
        modelAndView.setViewName("sm.jsp");
        return modelAndView;
    }
}

这样子就会访问/test/ww.do

@ResultMapping也可以指定请求方法

请求参数

就直接在方法名后面接收参数就行了

public ModelAndView doSome(HttpServletRequest request, 
                           HttpServletResponse response,
                           HttpSession session){}

请求参数也可以按照顺序直接输入具体的参数:

public ModelAndView doSome(String name, int age){}

或者使用annotation指定参数的名称:

public ModelAndView doSome(@RequestParam("rname" required=false) String name, @RequestParam("rage") int age){}

这样子会自动执行如下操作:

//使用request对象接收参数
String strName = request.getParameter("name");
String strAge = request.getParameter("age");

//mvc框架通过DispatcherServlet调用doSome方法
doSome(strName, Integer.valueOf(strAge))

还可以使用类的方法获取参数

    @RequestMapping("/qq.do")
    public ModelAndView doOther(Student student){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("name", student.getName());
        modelAndView.addObject("age", student.getAge());
        modelAndView.setViewName("sm");
        return modelAndView;
    }

原理和setter注入差不多,request参数为name,就会给student执行setName()方法

添加encoding Filter防止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>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

使用json

1、利用HttpServletResponse

    @RequestMapping("aa.do")
    public void doVoid(Student student, HttpServletResponse response) throws IOException {
        PrintWriter writer = response.getWriter();
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(student);
        writer.println(json);
        writer.flush();
        writer.close();
    }

2、利用注解

	@RequestMapping(value = "/cc.do", method = RequestMethod.POST)
    @ResponseBody
    public Student doCC(String name, Integer age){
        Student student1 = new Student();
        student1.setAge(age);
        student1.setName(name);
        return student1;
    }

使用注解的时候我们还需要添加依赖和注解驱动,
依赖 pom.xml:

 <dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.9.5</version>
</dependency>
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-annotations</artifactId>
   <version>2.9.2</version>
</dependency>

驱动 context.xml

<mvc:annotation-driven >
	<mvc:message-converters>
		<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
		<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
	</mvc:message-converters>
</mvc:annotation-driven>

或者

<mvc:annotation-driven />

这个驱动默认添加有HttpMessageConverter的7个实现类
我们也可以指定添加哪些实现类

这个HttpMessageConverter接口有四个方法:

  • canRead
  • canWrite
  • read
  • write
    他是先使用canWrite检验我们的方法返回值Object能不能转换成为json,然后使用write将我们的Object转换为json
    这个write方法就做了类似上面void返回值时候我们做的事情:
        String json = objectMapper.writeValueAsString(student);

使用注解@ResponseBody的时候,方法返回的Object,包括String类型的,都是数据
不适用这个注解的时候,方法返回如果为String,那么这个String就是view的路径

URL

指的是在静态文件里的路径,比如HTML文件里的<a>标签

绝对路径

也不是真的绝对路径,而是以/开头的路径
那么默认的/的前面就是项目的主URL,也就是启动项目时,浏览器自动打开的URL
有个叫pageContext.request.contextPath的对象,他表示的就是项目的主URL

相对路径

就是相对于当前URL的路径,比如相对路径为cc,当前URL为http://www.baidu.com/aa,那么就会去http://www.baidu.com/aa/cc
我们可以在静态资源页面中写上<base href="http://www.baidu.com/aa"/>那么这个页面中所有的相对路径就都是相对于这个base标签的了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值