前言:
小伙伴们,大家好,我是狂奔の蜗牛rz,当然你们可以叫我蜗牛君,我是一个学习Java半年多时间的小菜鸟,同时还有一个伟大的梦想,那就是有朝一日,成为一个优秀的Java架构师。
这个SpringMVC基础学习系列是用来记录我学习SpringMVC框架基础知识的全过程 (这个系列是参照B站狂神的SpringMVC最新教程来写的,由于是之前整理的,但当时没有发布出来,所以有些地方可能有错误,希望大家能够及时指正!)
之后我将尽量以两天一更的速度更新这个系列,还没有学习SpringMVC框架的小伙伴可以参照我的博客学习一下;当然学习过的小伙伴,也可以顺便跟我一起复习一下基础。最后,希望能够和大家一同进步吧,加油吧,编程人!
特别提醒:如果对SpringMVC基础学习系列感兴趣,可以阅读本系列往期博客:
第一篇:SpringMVC基础学习之简单回顾MVC架构和Servlet的使用
第二篇:SpringMVC基础学习之初识SpringMVC
第三篇:SpringMVC基础学习之初识
第四篇:SpringMVC基础学习之使用注解开发
今天我们来到了SpringMVC基础学习的第五站:Controller的两种实现方式和RequstMapping注解的使用 。废话不多说,让我们开始今天的学习内容吧。
5.Controller的两种实现方式和RequstMapping注解的使用
5.1 什么是Controller?
- Controller (即控制器) ,它主要负责提供访问应用程序的行为和解析用户的请求,并将其转换为一个模型,通常通过接口定义或注解定义这两种方式来实现
- 在Spring MVC中一个控制器类可以包含多个方法,并且对于 Controller的配置方式 包含多种,包括接口定义和注解定义
5.2 实现Controller接口
5.1.1 了解Controller接口
- Controller是一个接口,在org.springframework.web.servlet.mvc包下,为了进一步了解它,我们可以查看其源代码:
// 实现该接口的类获得控制器功能
public interface Controller {
// 处理请求并返回一个模型与视图对象
ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}
查看Controller接口的源码后,发现该接口中只有一个方法,即handleRequest方法,用来处理请求并返回一个ModelAndView(模型和视图)对象
5.1.2 创建HelloController类
- 在src源文件下的java目录中创建一个com.kuang.controller包,创建HelloController类并且实现Controller接口
package com.kuang.controller;
import org.springframework.web.servlet.ModelAndView;
// 注意: 该Controller接口是servlet.mvc包下
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 只要实现了Controller接口的类,说明这就是一个控制器了
public class HelloController implements Controller {
/**
* 用于处理请求并返回一个模型与视图对象
* @param: httpServletRequest http请求
* @param: httpServletResponse http响应
* @return ModelAndView 视图模型对象
*/
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
// 获取ModelAndView(模型视图)对象
ModelAndView mv = new ModelAndView();
// 封装数据到ModelAndView对象中
mv.addObject("msg","Hello,Controller!");
// 设置跳转视图, 存入到ModelAndView对象中
mv.setViewName("hello");
// 返回视图模型对象给视图解析器
return mv;
}
}
5.1.3 编写核心配置文件
1.编写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(前端控制器), SpringMVC中的核心,相当于请求分发器 -->
<!-- 配置servlet -->
<servlet>
<!-- servlet的名字,自行设置 -->
<servlet-name>springmvc</servlet-name>
<!-- DispatcherServlet类的位置 -->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<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>
<!-- 配置servlet映射 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 注意:在SpringMVC中, / 和 /* 作用不同
/ : 匹配所有的请求,不会匹配jsp页面
/*: 匹配所有的请求,包括jsp页面 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.编写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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 显式引入处理器映射和处理器适配器,也可以不写,因为Spring已经帮我们引入了 -->
<!-- 配置处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 配置处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- 配置internalResourceViewResolver(视图解析器), 主要作用是解析DispatcherServlet(中心控制器)给它的ModelAndView -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀 -->
<property name="suffix" value=".jsp"/>
<!-- 注意: 在视图解析器中我们吧所有的视图都放在/WEB-INF/目录下, 这样可以保证视图安全,因为这个目录下的文件,客户端不能直接访问) -->
</bean>
<!-- 注册控制器HelloController的Bean信息,交由Spring的IOC容器进行管理;
该bean标签中的包含两个属性class和name, 其中"class"对应处理请求的控制类, 而"name"对应请求路径-->
<bean class="com.kuang.controller.HelloController" name="/hello"/>
</beans>
5.1.4 实现Controller接口使用总结
优点:
- 逻辑简单,易于理解
- 比起使用传统的Servlet,配置文件的编写简便了许多
缺点:
- 与使用注解相比,配置文件和控制层代码还是略过繁琐
- 每个控制层只能控制一个跳转页面,页面无法复用
5.3 使用@Controller注解
5.1.1 了解常用注解
@Component:注册为组件
@Repository:注册为Dao持久层
@Service:注册为Service服务层
@Controller:注册为Controller控制层
5.1.2 创建HelloController控制器类
- 在src源文件下的java目录下创建一个com.kuang.controller包,创建HelloController2类
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
// 使用@Controller注解, 将其注册为控制层, 由Spring的IOC容器统一管理
@Controller
public class HelloController2 {
/**
* 使用@Controller注解注解的类中的所有方法,
* 如果返回类型是String, 并且有具体的页面可以跳转, 那么就会被视图解析器解析
*/
// 使用@RequestMapping注解, 设置请求映射, 其作用域是类或者方法
@RequestMapping("/h1")
public String hello(Model model) {
// 封装数据:向模型中添加属性msg与其值,可以在JSP页面取出并且渲染
model.addAttribute("msg","Hello,Controller!");
// 会被视图解析器处理,注意:这里的hello对应的是JSP页面的名字
return "hello";
}
// 使用@RequestMapping注解, 设置请求映射, 其作用域是类或者方法
@RequestMapping("/h2")
public String hello2(Model model) {
// 封装数据: 向模型中添加属性msg与其值,可以在JSP页面取出并且渲染
model.addAttribute("msg","Hello,World!");
// 会被视图解析器处理(注意: 这里的hello对应的是JSP页面的名字)
return "hello";
}
}
5.1.3 编写核心配置文件
1.编写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(前端控制器), SpringMVC中的核心,相当于请求分发器 -->
<!-- 配置servlet -->
<servlet>
<!-- servlet的名字,自行设置 -->
<servlet-name>springmvc</servlet-name>
<!-- DispatcherServlet类的位置 -->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<!-- 设置配置文件的位置 -->
<param-name>contextConfigLocation</param-name>
<!-- 配置文件的路径 -->
<param-value>classpath:springmvc-servlet2.xml</param-value>
</init-param>
<!-- 设置启动优先级为1 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 配置servlet映射 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!-- 注意:在SpringMVC中, / 和 /* 作用不同
/ : 匹配所有的请求,不会匹配jsp页面
/*: 匹配所有的请求,包括jsp页面 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2.编写springmvc-servlet2.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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
<context:component-scan base-package="com.kuang.controller"/>
<!-- 设置default-servlet-handler用来防止静态资源被过滤 -->
<mvc:default-servlet-handler/>
<!-- 设置mvc的注解驱动, 让@RequstMapping注解生效以及引入DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter实例;
使用annotation-driven会帮助我们自动完成上述两个实例的注入 -->
<mvc:annotation-driven/>
<!-- 配置internalResourceViewResolve(视图解析器): 主要作用是解析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>
5.1.4 测试结果
1.访问h1页面
2.访问h2页面
结果:可以发现,我们的两个请求都指向一个视图,但是页面结果却是不一样的,从这里可以看出视图是被复用的,因此控制器与视图之间是弱耦合关系
5.1.5 使用@Controller注解使用总结
优点:
- 使用注解开发,代码量大大减少,开发起来很方便
- 配置文件的编写比实现Controller接口的更加简便
- 一个控制器中可以写多个请求映射,从而实现跳转不同的视图
- 也可以跳转同一视图,但显示结果不同,视图可以被复用
缺点:
- 配置信息少,使用大量注解,导致查看代码结构时不太方便
- 代码可读性降低,不方便后期的代码维护
5.4 使用@RequstMapping注解
5.4.1 只在方法上使用
1.编写HelloController3对象
1-1 使用正常路径
- hello.jsp页面的存放路径为WEB-INF/jsp/hello.jsp
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
// 使用@Controller注解, 将该类注册为Controller接口, 交由Spring的IOC容器统一管理
@Controller
public class HelloController3 {
/**
* 在hello()方法上使用@RequestMapping, 设置请求映射路径
* 而真实访问路径为:http://localhost:8080/项目名称/hello
*/
@RequestMapping("/hello")
public String hello(Model model) {
// 封装数据: 向模型中添加属性msg与其值,进行视图渲染
model.addAttribute("msg","Hello,RequestMapping!");
// 返回视图逻辑名,让视图解析器进行解析(注意:这里的hello是要跳转的视图逻辑名)
return "hello";
}
}
1-2 修改路径后
- 将hello.jsp的存放路径修改为WEB-INF/jsp/user/hello.jsp,即在jsp文件下创建一个user,将hello.jsp放入其中
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
// 使用@Controller注解, 将该类注册为Controller接口, 交由Spring的IOC容器统一管理
@Controller
public class HelloController3 {
/**
* 使用@RequestMapping, 设置请求映射路径 (注意: 直接在方法上把路径补全)
* 真实访问路径为:http://localhost:8080/项目名称/user/hello
*/
@RequestMapping("/user/hello3")
public String hello3(Model model) {
// 封装数据: 向模型中添加属性msg与其值,进行视图渲染
model.addAttribute("msg","Hello,User!");
// 返回视图逻辑名,让视图解析器进行解析 (注意: 由于路径发生了改变,因此要跳转的视图逻辑名也要相应变化)
return "hello/user";
}
}
建议这样使用@RequestMapping注解,即在方法前的映射请求中设置全路径
2.测试结果
2-1 使用正常路径
结果:成功查询到了hello2页面,并且显示“Hello,RequestMapping!”信息
2-2 修改路径后
结果:成功查询到了user/hello3页面,并且显示“Hello,User”信息!
5.4.2 在类和方法上同时使用
1.修改HelloController3控制类
- hello.jsp的存放路径仍然为WEB-INF/jsp/user/hello.jsp
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
// 使用@Controller注解, 将该类注册为Controller接口, 交由Spring的IOC容器统一管理
@Controller
// 在控制类上使用@RequestMapping: 相当于在URL链接上再加一个父目录进行区分
@RequestMapping("/user") // 先访问类上的/user
public class HelloController3 {
// 真实访问路径变为了:http://localhost:8080/项目名称/user/hello2
@RequestMapping("/hello2") //再访问/hello2
public String hello2(Model model) {
// 封装数据:向模型中添加属性msg与值,进行视图渲染
model.addAttribute("msg","Hello,RequestMapping2!");
// 返回视图逻辑名,让视图解析器进行解析 (注意: 由于路径发生了改变,因此要跳转的视图逻辑名也要相应变化)
return "user/hello";
}
}
2.测试结果
结果:成功查询到了user/hello2页面,并且显示“Hello,RequestMapping2!”信息
5.4.3 使用总结
- 只在方法上使用@RequestMapping注解,代码编写更加简便,只用在每个方法前设置映射关系,而且方法中的页面的路径选择更加宽泛
- 在类和方法上同时使用@RequestMapping注解,逻辑更加清晰,但页面的调用范围也受到了限制,即只能调用在类上的映射关系中设置的父目录下的页面
好了,今天的有关 Controller的两种实现方式和RequstMapping注解的使用 的学习就到此结束啦。欢迎小伙伴们积极学习和讨论,喜欢的可以给蜗牛君点个关注,顺便来个一键三连。我们下期见,拜拜啦!